From 215838db1bcd62bf4da5b9ca14c3fc46964de56e Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 6 Mar 2023 21:04:02 +0200 Subject: [PATCH] ESP32 LVGL library from v8.3.3 to v8.3.5 (no functional change) (#18128) --- CHANGELOG.md | 1 + lib/libesp32_lvgl/lvgl/library.json | 2 +- lib/libesp32_lvgl/lvgl/library.properties | 2 +- lib/libesp32_lvgl/lvgl/lv_conf_template.h | 5 +- lib/libesp32_lvgl/lvgl/lvgl.h | 2 +- lib/libesp32_lvgl/lvgl/src/core/lv_indev.c | 23 +- .../lvgl/src/core/lv_indev_scroll.c | 131 +-- lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c | 18 +- lib/libesp32_lvgl/lvgl/src/core/lv_refr.c | 10 + .../lvgl/src/draw/arm2d/lv_gpu_arm2d.c | 340 ++++++-- lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h | 1 + lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c | 9 +- .../lvgl/src/draw/nxp/lv_draw_nxp.mk | 2 - .../lvgl/src/draw/nxp/lv_gpu_nxp.c | 418 --------- .../lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk | 1 + .../lvgl/src/draw/nxp/pxp/lv_draw_pxp.c | 250 ++++++ .../nxp/{lv_gpu_nxp.h => pxp/lv_draw_pxp.h} | 25 +- .../lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c | 353 +++----- .../lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h | 87 +- .../lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c | 36 +- .../lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h | 19 +- .../src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c | 46 +- .../src/draw/nxp/vglite/lv_draw_nxp_vglite.mk | 5 +- .../lvgl/src/draw/nxp/vglite/lv_draw_vglite.c | 508 +++++++++++ .../lvgl/src/draw/nxp/vglite/lv_draw_vglite.h | 72 ++ .../src/draw/nxp/vglite/lv_draw_vglite_arc.c | 148 ++-- .../src/draw/nxp/vglite/lv_draw_vglite_arc.h | 26 +- .../draw/nxp/vglite/lv_draw_vglite_blend.c | 734 ++++++++-------- .../draw/nxp/vglite/lv_draw_vglite_blend.h | 95 +-- .../src/draw/nxp/vglite/lv_draw_vglite_line.c | 138 +++ .../src/draw/nxp/vglite/lv_draw_vglite_line.h | 83 ++ .../src/draw/nxp/vglite/lv_draw_vglite_rect.c | 427 +++++++--- .../src/draw/nxp/vglite/lv_draw_vglite_rect.h | 34 +- .../src/draw/nxp/vglite/lv_gpu_nxp_vglite.c | 153 ---- .../lvgl/src/draw/nxp/vglite/lv_vglite_buf.c | 143 ++++ .../lvgl/src/draw/nxp/vglite/lv_vglite_buf.h | 113 +++ .../src/draw/nxp/vglite/lv_vglite_utils.c | 149 ++++ ...{lv_gpu_nxp_vglite.h => lv_vglite_utils.h} | 83 +- .../lvgl/src/draw/sdl/lv_draw_sdl_rect.c | 281 +++++- .../lvgl/src/draw/sdl/lv_draw_sdl_rect.h | 5 + .../src/draw/sdl/lv_draw_sdl_texture_cache.h | 1 + .../src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c | 798 ++++++++++++++---- .../src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h | 77 +- .../lvgl/src/draw/sw/lv_draw_sw_blend.c | 13 +- .../lvgl/src/draw/sw/lv_draw_sw_letter.c | 4 +- .../lvgl/src/draw/sw/lv_draw_sw_transform.c | 12 +- .../lvgl/src/extra/layouts/flex/lv_flex.c | 10 +- .../src/extra/others/gridnav/lv_gridnav.c | 1 + .../lvgl/src/extra/others/monkey/lv_monkey.c | 0 .../lvgl/src/extra/others/monkey/lv_monkey.h | 0 .../lvgl/src/extra/others/msg/lv_msg.h | 11 + .../src/extra/widgets/animimg/lv_animimg.c | 2 +- .../src/extra/widgets/animimg/lv_animimg.h | 4 +- .../lvgl/src/extra/widgets/chart/lv_chart.c | 9 +- .../lvgl/src/extra/widgets/meter/lv_meter.c | 1 + lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c | 17 +- lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h | 1 + lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h | 3 + lib/libesp32_lvgl/lvgl/src/misc/lv_style.h | 5 - .../lvgl/src/widgets/lv_roller.c | 3 + lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c | 26 + 61 files changed, 3984 insertions(+), 1992 deletions(-) delete mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c rename lib/libesp32_lvgl/lvgl/src/draw/nxp/{lv_gpu_nxp.h => pxp/lv_draw_pxp.h} (77%) create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h delete mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h create mode 100644 lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c rename lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/{lv_gpu_nxp_vglite.h => lv_vglite_utils.h} (65%) mode change 100755 => 100644 lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.c mode change 100755 => 100644 lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.h diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbf6e258..157a5a6f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Changed - Refactored Berry rule engine and support for arrays +- ESP32 LVGL library from v8.3.3 to v8.3.5 (no functional change) ### Fixed - TuyaMcu v1 sequence fix (#17625) diff --git a/lib/libesp32_lvgl/lvgl/library.json b/lib/libesp32_lvgl/lvgl/library.json index fe8ef4c15..9f9ade2c9 100644 --- a/lib/libesp32_lvgl/lvgl/library.json +++ b/lib/libesp32_lvgl/lvgl/library.json @@ -1,6 +1,6 @@ { "name": "lvgl", - "version": "8.3.3", + "version": "8.3.5", "keywords": "graphics, gui, embedded, tft, lvgl", "description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.", "repository": { diff --git a/lib/libesp32_lvgl/lvgl/library.properties b/lib/libesp32_lvgl/lvgl/library.properties index 816446a93..ae036fdbe 100644 --- a/lib/libesp32_lvgl/lvgl/library.properties +++ b/lib/libesp32_lvgl/lvgl/library.properties @@ -1,5 +1,5 @@ name=lvgl -version=8.3.3 +version=8.3.5 author=kisvegabor maintainer=kisvegabor,embeddedt,pete-pjb sentence=Full-featured Graphics Library for Embedded Systems diff --git a/lib/libesp32_lvgl/lvgl/lv_conf_template.h b/lib/libesp32_lvgl/lvgl/lv_conf_template.h index 3d087f0f3..c5b67a34e 100644 --- a/lib/libesp32_lvgl/lvgl/lv_conf_template.h +++ b/lib/libesp32_lvgl/lvgl/lv_conf_template.h @@ -1,6 +1,6 @@ /** * @file lv_conf.h - * Configuration file for v8.3.3 + * Configuration file for v8.3.5 */ /* @@ -89,6 +89,9 @@ #if LV_TICK_CUSTOM #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ + /*If using lvgl as ESP32 component*/ + // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" + // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. diff --git a/lib/libesp32_lvgl/lvgl/lvgl.h b/lib/libesp32_lvgl/lvgl/lvgl.h index c0be411b2..76f22761b 100644 --- a/lib/libesp32_lvgl/lvgl/lvgl.h +++ b/lib/libesp32_lvgl/lvgl/lvgl.h @@ -15,7 +15,7 @@ extern "C" { ***************************/ #define LVGL_VERSION_MAJOR 8 #define LVGL_VERSION_MINOR 3 -#define LVGL_VERSION_PATCH 3 +#define LVGL_VERSION_PATCH 5 #define LVGL_VERSION_INFO "" /********************* diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c b/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c index ab1265ec8..caf9c3178 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c @@ -852,8 +852,6 @@ static void indev_proc_press(_lv_indev_proc_t * proc) if(indev_reset_check(proc)) return; } - lv_obj_transform_point(indev_obj_act, &proc->types.pointer.act_point, true, true); - /*If a new object was found reset some variables and send a pressed event handler*/ if(indev_obj_act != proc->types.pointer.act_obj) { proc->types.pointer.last_point.x = proc->types.pointer.act_point.x; @@ -987,6 +985,27 @@ static void indev_proc_release(_lv_indev_proc_t * proc) proc->pr_timestamp = 0; proc->longpr_rep_timestamp = 0; + + /*Get the transformed vector with this object*/ + if(scroll_obj) { + int16_t angle = 0; + int16_t zoom = 256; + lv_point_t pivot = { 0, 0 }; + lv_obj_t * parent = scroll_obj; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); + } + + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_transform(&proc->types.pointer.scroll_throw_vect, angle, zoom, &pivot); + lv_point_transform(&proc->types.pointer.scroll_throw_vect_ori, angle, zoom, &pivot); + } + } + } /*The reset can be set in the Call the ancestor's event handler function. diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c b/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c index c05e3459f..3a7318316 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c @@ -45,12 +45,13 @@ static lv_coord_t elastic_diff(lv_obj_t * scroll_obj, lv_coord_t diff, lv_coord_ void _lv_indev_scroll_handler(_lv_indev_proc_t * proc) { + if(proc->types.pointer.vect.x == 0 && proc->types.pointer.vect.y == 0) { + return; + } + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; /*If there is no scroll object yet try to find one*/ if(scroll_obj == NULL) { - proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; - proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; - scroll_obj = find_scroll_obj(proc); if(scroll_obj == NULL) return; @@ -61,35 +62,50 @@ void _lv_indev_scroll_handler(_lv_indev_proc_t * proc) } /*Set new position or scroll if the vector is not zero*/ - if(proc->types.pointer.vect.x != 0 || proc->types.pointer.vect.y != 0) { - lv_coord_t diff_x = 0; - lv_coord_t diff_y = 0; - - if(proc->types.pointer.scroll_dir == LV_DIR_HOR) { - lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); - lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); - diff_x = elastic_diff(scroll_obj, proc->types.pointer.vect.x, sl, sr, LV_DIR_HOR); - } - else { - lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); - lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); - diff_y = elastic_diff(scroll_obj, proc->types.pointer.vect.y, st, sb, LV_DIR_VER); - } - - lv_dir_t scroll_dir = lv_obj_get_scroll_dir(scroll_obj); - if((scroll_dir & LV_DIR_LEFT) == 0 && diff_x > 0) diff_x = 0; - if((scroll_dir & LV_DIR_RIGHT) == 0 && diff_x < 0) diff_x = 0; - if((scroll_dir & LV_DIR_TOP) == 0 && diff_y > 0) diff_y = 0; - if((scroll_dir & LV_DIR_BOTTOM) == 0 && diff_y < 0) diff_y = 0; - - /*Respect the scroll limit area*/ - scroll_limit_diff(proc, &diff_x, &diff_y); - - _lv_obj_scroll_by_raw(scroll_obj, diff_x, diff_y); - if(proc->reset_query) return; - proc->types.pointer.scroll_sum.x += diff_x; - proc->types.pointer.scroll_sum.y += diff_y; + int16_t angle = 0; + int16_t zoom = 256; + lv_obj_t * parent = scroll_obj; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); } + + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_t pivot = { 0, 0 }; + lv_point_transform(&proc->types.pointer.vect, angle, zoom, &pivot); + } + + + + lv_coord_t diff_x = 0; + lv_coord_t diff_y = 0; + if(proc->types.pointer.scroll_dir == LV_DIR_HOR) { + lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); + lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); + diff_x = elastic_diff(scroll_obj, proc->types.pointer.vect.x, sl, sr, LV_DIR_HOR); + } + else { + lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); + lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); + diff_y = elastic_diff(scroll_obj, proc->types.pointer.vect.y, st, sb, LV_DIR_VER); + } + + lv_dir_t scroll_dir = lv_obj_get_scroll_dir(scroll_obj); + if((scroll_dir & LV_DIR_LEFT) == 0 && diff_x > 0) diff_x = 0; + if((scroll_dir & LV_DIR_RIGHT) == 0 && diff_x < 0) diff_x = 0; + if((scroll_dir & LV_DIR_TOP) == 0 && diff_y > 0) diff_y = 0; + if((scroll_dir & LV_DIR_BOTTOM) == 0 && diff_y < 0) diff_y = 0; + + /*Respect the scroll limit area*/ + scroll_limit_diff(proc, &diff_x, &diff_y); + + _lv_obj_scroll_by_raw(scroll_obj, diff_x, diff_y); + if(proc->reset_query) return; + proc->types.pointer.scroll_sum.x += diff_x; + proc->types.pointer.scroll_sum.y += diff_y; } @@ -99,7 +115,6 @@ void _lv_indev_scroll_throw_handler(_lv_indev_proc_t * proc) if(scroll_obj == NULL) return; if(proc->types.pointer.scroll_dir == LV_DIR_NONE) return; - lv_indev_t * indev_act = lv_indev_get_act(); lv_coord_t scroll_throw = indev_act->driver->scroll_throw; @@ -259,14 +274,36 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) /*Decide if it's a horizontal or vertical scroll*/ bool hor_en = false; bool ver_en = false; - if(LV_ABS(proc->types.pointer.scroll_sum.x) > LV_ABS(proc->types.pointer.scroll_sum.y)) { - hor_en = true; - } - else { - ver_en = true; - } + + proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; + proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; while(obj_act) { + /*Get the transformed scroll_sum with this object*/ + int16_t angle = 0; + int16_t zoom = 256; + lv_point_t pivot = { 0, 0 }; + lv_obj_t * parent = obj_act; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); + } + + lv_point_t obj_scroll_sum = proc->types.pointer.scroll_sum; + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_transform(&obj_scroll_sum, angle, zoom, &pivot); + } + + if(LV_ABS(obj_scroll_sum.x) > LV_ABS(obj_scroll_sum.y)) { + hor_en = true; + } + else { + ver_en = true; + } + if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLLABLE) == false) { /*If this object don't want to chain the scroll to the parent stop searching*/ if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLL_CHAIN_HOR) == false && hor_en) break; @@ -300,15 +337,15 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) *is propagated to this object it can show at least elastic scroll effect. *But if not hor/ver scrollable do not scroll it at all (so it's not a good candidate)*/ if((st > 0 || sb > 0) && - ((up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit))) { + ((up_en && obj_scroll_sum.y >= scroll_limit) || + (down_en && obj_scroll_sum.y <= - scroll_limit))) { obj_candidate = obj_act; dir_candidate = LV_DIR_VER; } if((sl > 0 || sr > 0) && - ((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit))) { + ((left_en && obj_scroll_sum.x >= scroll_limit) || + (right_en && obj_scroll_sum.x <= - scroll_limit))) { obj_candidate = obj_act; dir_candidate = LV_DIR_HOR; } @@ -318,11 +355,11 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) if(sl <= 0) left_en = false; if(sr <= 0) right_en = false; - /*If the object really can be scrolled into the current direction the use it.*/ - if((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit) || - (up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit)) { + /*If the object really can be scrolled into the current direction then use it.*/ + if((left_en && obj_scroll_sum.x >= scroll_limit) || + (right_en && obj_scroll_sum.x <= - scroll_limit) || + (up_en && obj_scroll_sum.y >= scroll_limit) || + (down_en && obj_scroll_sum.y <= - scroll_limit)) { proc->types.pointer.scroll_dir = hor_en ? LV_DIR_HOR : LV_DIR_VER; break; } diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c b/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c index a31c11db8..5fc7db9ee 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c @@ -1160,9 +1160,21 @@ static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv) if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) return; - lv_point_t pivot; - pivot.x = obj->coords.x1 + lv_obj_get_style_transform_pivot_x(obj, 0); - pivot.y = obj->coords.y1 + lv_obj_get_style_transform_pivot_y(obj, 0); + lv_point_t pivot = { + .x = lv_obj_get_style_transform_pivot_x(obj, 0), + .y = lv_obj_get_style_transform_pivot_y(obj, 0) + }; + + if(LV_COORD_IS_PCT(pivot.x)) { + pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100; + } + if(LV_COORD_IS_PCT(pivot.y)) { + pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100; + } + + pivot.x = obj->coords.x1 + pivot.x; + pivot.y = obj->coords.y1 + pivot.y; + if(inv) { angle = -angle; zoom = (256 * 256) / zoom; diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c b/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c index 1a56fed0b..45ff2e0e7 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c @@ -613,6 +613,9 @@ static void refr_area_part(lv_draw_ctx_t * draw_ctx) { lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); + if(draw_ctx->init_buf) + draw_ctx->init_buf(draw_ctx); + /* Below the `area_p` area will be redrawn into the draw buffer. * In single buffered mode wait here until the buffer is freed. * In full double buffered mode wait here while the buffers are swapped and a buffer becomes available*/ @@ -914,6 +917,13 @@ void refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj) .y = lv_obj_get_style_transform_pivot_y(obj, 0) }; + if(LV_COORD_IS_PCT(pivot.x)) { + pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100; + } + if(LV_COORD_IS_PCT(pivot.y)) { + pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100; + } + lv_draw_img_dsc_t draw_dsc; lv_draw_img_dsc_init(&draw_dsc); draw_dsc.opa = opa; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c b/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c index 7777fe21b..f294125be 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c @@ -39,6 +39,7 @@ #include "../../core/lv_refr.h" #if LV_USE_GPU_ARM2D +#define __ARM_2D_IMPL__ #include "arm_2d.h" #include "__arm_2d_impl.h" @@ -89,10 +90,12 @@ #define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb16_cl_key_copy #define __arm_2d_impl_alpha_blending_colour_keying \ __arm_2d_impl_rgb565_alpha_blending_colour_keying -#define arm_2d_tile_transform_with_src_mask_and_opacity \ - arm_2d_rgb565_tile_transform_with_src_mask_and_opacity -#define arm_2d_tile_transform_with_opacity \ - arm_2d_rgb565_tile_transform_with_opacity +#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \ + arm_2dp_rgb565_tile_transform_with_src_mask_and_opacity_prepare +#define arm_2d_tile_transform_with_opacity_prepare \ + arm_2dp_rgb565_tile_transform_with_opacity_prepare +#define arm_2d_tile_transform_prepare \ + arm_2dp_rgb565_tile_transform_prepare #define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_RGB565 @@ -124,10 +127,12 @@ #define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb32_cl_key_copy #define __arm_2d_impl_alpha_blending_colour_keying \ __arm_2d_impl_cccn888_alpha_blending_colour_keying -#define arm_2d_tile_transform_with_src_mask_and_opacity \ - arm_2d_cccn888_tile_transform_with_src_mask_and_opacity -#define arm_2d_tile_transform_with_opacity \ - arm_2d_cccn888_tile_transform_with_opacity +#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \ + arm_2dp_cccn888_tile_transform_with_src_mask_and_opacity_prepare +#define arm_2d_tile_transform_with_opacity_prepare \ + arm_2dp_cccn888_tile_transform_with_opacity_prepare +#define arm_2d_tile_transform_prepare \ + arm_2dp_cccn888_tile_transform_prepare #define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_CCCN888 @@ -298,11 +303,88 @@ /* replace src_buf for the following operation */ \ src_buf = (const uint8_t *)rgb_tmp_buf; \ } \ - __VA_ARGS__ \ + do { \ + __VA_ARGS__ \ + } while(0); \ if (NULL != rgb_tmp_buf) { \ lv_mem_buf_release(rgb_tmp_buf); \ } \ - } while(0); + } while(0); \ + src_buf = src_buf_org; + +#define __RECOLOUR_BEGIN() \ + do { \ + lv_color_t *rgb_tmp_buf = NULL; \ + if(draw_dsc->recolor_opa > LV_OPA_MIN) { \ + rgb_tmp_buf \ + = lv_malloc(src_w * src_h * sizeof(lv_color_t)); \ + if (NULL == rgb_tmp_buf) { \ + LV_LOG_WARN( \ + "Failed to allocate memory for accelerating recolour, " \ + "use normal route instead."); \ + break; \ + } \ + lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\ + arm_2d_size_t copy_size = { \ + .iWidth = src_w, \ + .iHeight = src_h, \ + }; \ + /* apply re-colour */ \ + __arm_2d_impl_colour_filling_with_opacity( \ + (color_int *)rgb_tmp_buf, \ + src_w, \ + ©_size, \ + (color_int)draw_dsc->recolor.full, \ + draw_dsc->recolor_opa); \ + \ + /* replace src_buf for the following operation */ \ + src_buf = (const uint8_t *)rgb_tmp_buf; \ + } \ + do { + +#define __RECOLOUR_END() \ + } while(0); \ + if (NULL != rgb_tmp_buf) { \ + lv_free(rgb_tmp_buf); \ + } \ + } while(0); \ + src_buf = src_buf_org; + +#define __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(__TRANS_PREPARE, ...) \ + do { \ + __TRANS_PREPARE( \ + NULL, \ + __VA_ARGS__); \ + \ + target_region = (arm_2d_region_t) { \ + .tLocation = { \ + .iX = coords->x1 - draw_ctx->clip_area->x1, \ + .iY = coords->y1 - draw_ctx->clip_area->y1, \ + }, \ + .tSize = { \ + .iWidth = lv_area_get_width(coords), \ + .iHeight = lv_area_get_height(coords), \ + }, \ + }; \ + \ + arm_2d_size_t tTransSize \ + = ARM_2D_CTRL.DefaultOP \ + .tTransform.Source.ptTile->tRegion.tSize; \ + \ + if (target_region.tSize.iWidth < tTransSize.iWidth) { \ + int16_t iDelta = tTransSize.iWidth - target_region.tSize.iWidth;\ + target_region.tLocation.iX -= iDelta / 2; \ + target_region.tSize.iWidth = tTransSize.iWidth; \ + } \ + \ + if (target_region.tSize.iHeight < tTransSize.iHeight) { \ + int16_t iDelta \ + = tTransSize.iHeight - target_region.tSize.iHeight; \ + target_region.tLocation.iY -= iDelta / 2; \ + target_region.tSize.iHeight = tTransSize.iHeight; \ + } \ + } while(0) + /* *INDENT-ON* */ /********************** @@ -601,18 +683,26 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend lv_area_t blend_area; if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + //lv_disp_t * disp = _lv_refr_get_disp_refreshing(); bool is_accelerated = false; do { - if(NULL != disp->driver->set_px_cb) { - break; + + /* target buffer */ + lv_color_t * dest_buf = draw_ctx->buf; + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver->screen_transp == 0) { + dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); + } + else { + /*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/ + uint8_t * dest_buf8 = (uint8_t *) dest_buf; + dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE; + dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE; + dest_buf = (lv_color_t *)dest_buf8; } - lv_color_t * dest_buf = draw_ctx->buf; - dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) - + (blend_area.x1 - draw_ctx->buf_area->x1); - + /* source buffer */ const lv_color_t * src_buf = dsc->src_buf; lv_coord_t src_stride; if(src_buf) { @@ -634,7 +724,9 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - + if(disp->driver->screen_transp) { + break; + } if(dsc->src_buf == NULL) { if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { is_accelerated = arm_2d_fill_normal(dest_buf, @@ -645,14 +737,8 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend mask, mask_stride); } -#if LV_DRAW_COMPLEX - else { - break; - } -#endif } else { - if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { is_accelerated = arm_2d_copy_normal(dest_buf, &blend_area, @@ -663,11 +749,6 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend mask, mask_stride); } -#if LV_DRAW_COMPLEX - else { - break; - } -#endif } } while(0); @@ -698,15 +779,11 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, } /*Has opacity*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_colour_filling_with_opacity((color_int *)dest_buf, dest_stride, &target_size, color.full, opa); -#endif } } /*Masked*/ @@ -722,9 +799,6 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, } /*With opacity*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_colour_filling_mask_opacity((color_int *)dest_buf, dest_stride, (uint8_t *)mask, @@ -732,7 +806,6 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, &target_size, color.full, opa); -#endif } } @@ -759,10 +832,6 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, .iHeight = lv_area_get_height(dest_area), }; -#if LV_COLOR_SCREEN_TRANSP - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); -#endif - /*Simple fill (maybe with opacity), no masking*/ if(mask == NULL) { if(opa >= LV_OPA_MAX) { @@ -773,25 +842,18 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, ©_size); } else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_alpha_blending((color_int *)src_buf, src_stride, (color_int *)dest_buf, dest_stride, ©_size, opa); -#endif } } /*Masked*/ else { /*Only the mask matters*/ if(opa > LV_OPA_MAX) { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_src_msk_copy((color_int *)src_buf, src_stride, (uint8_t *)mask, @@ -800,13 +862,9 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, (color_int *)dest_buf, dest_stride, ©_size); -#endif } /*Handle opa and mask values too*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_gray8_alpha_blending((uint8_t *)mask, mask_stride, (uint8_t *)mask, @@ -822,7 +880,6 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, (color_int *)dest_buf, dest_stride, ©_size); -#endif } } @@ -839,6 +896,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, /*Use the clip area as draw area*/ lv_area_t draw_area; lv_area_copy(&draw_area, draw_ctx->clip_area); + const uint8_t * src_buf_org = src_buf; bool mask_any = lv_draw_mask_is_any(&draw_area); bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false; @@ -851,6 +909,13 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, blend_dsc.blend_mode = draw_dsc->blend_mode; blend_dsc.blend_area = &blend_area; + if(lv_img_cf_is_chroma_keyed(cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; + else if(cf == LV_IMG_CF_ALPHA_8BIT) {} + else if(cf == LV_IMG_CF_RGB565A8) {} + else if(lv_img_cf_has_alpha(cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; + else cf = LV_IMG_CF_TRUE_COLOR; + + /*The simplest case just copy the pixels into the draw_buf*/ if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) { blend_dsc.src_buf = (const lv_color_t *)src_buf; @@ -859,6 +924,9 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, lv_draw_sw_blend(draw_ctx, &blend_dsc); } else if(!mask_any && !transform && cf == LV_IMG_CF_ALPHA_8BIT) { + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, coords, draw_ctx->clip_area)) return; + blend_dsc.mask_buf = (lv_opa_t *)src_buf; blend_dsc.mask_area = coords; blend_dsc.src_buf = NULL; @@ -869,7 +937,8 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, lv_draw_sw_blend(draw_ctx, &blend_dsc); } #if LV_COLOR_DEPTH == 16 - else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP) { + else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP && + blend_dsc.opa >= LV_OPA_MAX) { lv_coord_t src_w = lv_area_get_width(coords); lv_coord_t src_h = lv_area_get_height(coords); blend_dsc.src_buf = (const lv_color_t *)src_buf; @@ -922,6 +991,23 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; blend_dsc.mask_res = mask_res_def; + if(cf == LV_IMG_CF_ALPHA_8BIT) { + /* original code: + lv_color_fill(rgb_buf, draw_dsc->recolor, buf_size); + */ + arm_2d_size_t copy_size = { + .iWidth = buf_w, + .iHeight = buf_h, + }; + + /* apply re-colour */ + __arm_2d_impl_colour_filling( + (color_int *)rgb_buf, + buf_w, + ©_size, + (color_int)draw_dsc->recolor.full); + } + bool is_accelerated = false; if(!transform) { @@ -968,7 +1054,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, } else if((LV_COLOR_DEPTH == 32) && !mask_any - && (cf == LV_IMG_CF_TRUE_COLOR_ALPHA)) { + && (LV_IMG_CF_TRUE_COLOR_ALPHA == cf)) { /* accelerate copy-with-source-masks-and-opacity */ /* *INDENT-OFF* */ @@ -1025,6 +1111,63 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, ) /* *INDENT-ON* */ } + else if(!mask_any + && (LV_IMG_CF_RGB565A8 == cf)) { + /* accelerate copy-with-source-masks-and-opacity */ + + uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h; + /* *INDENT-OFF* */ + __RECOLOUR_WRAPPER( + __PREPARE_LL_ACCELERATION__(); + + uint8_t * mask_temp_buf = NULL; + if(blend_dsc.opa < LV_OPA_MAX) { + mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth); + if(NULL == mask_temp_buf) { + LV_LOG_WARN( + "Failed to allocate memory for alpha mask," + " use normal route instead."); + break; + } + lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth); + + __arm_2d_impl_gray8_colour_filling_mask_opacity( + mask_temp_buf, + src_stride, + mask_after_rgb, + src_stride, + ©_size, + 0xFF, + blend_dsc.opa); + + __arm_2d_impl_src_msk_copy( + (color_int *)src_buf_tmp, + src_stride, + mask_temp_buf, + src_stride, + ©_size, + (color_int *)dest_buf, + dest_stride, + ©_size); + + lv_mem_buf_release(mask_temp_buf); + } + else { + __arm_2d_impl_src_msk_copy( + (color_int *)src_buf_tmp, + src_stride, + mask_after_rgb, + src_stride, + ©_size, + (color_int *)dest_buf, + dest_stride, + ©_size); + } + + is_accelerated = true; + ) + /* *INDENT-ON* */ + } else if(!mask_any && (cf == LV_IMG_CF_TRUE_COLOR)) { /* accelerate copy-with-source-masks-and-opacity */ @@ -1063,6 +1206,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, && (draw_dsc->recolor_opa == LV_OPA_TRANSP) && (((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || (LV_IMG_CF_TRUE_COLOR == cf)) + || (LV_IMG_CF_RGB565A8 == cf) #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) && __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__ || ((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && (LV_COLOR_DEPTH == 32)) @@ -1070,6 +1214,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, ) ) { + uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h; /* *INDENT-OFF* */ __RECOLOUR_WRAPPER( /* accelerate transform without re-color */ @@ -1108,17 +1253,6 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, &target_tile, false); - target_region = (arm_2d_region_t) { - .tLocation = { - .iX = coords->x1 - draw_ctx->clip_area->x1, - .iY = coords->y1 - draw_ctx->clip_area->y1, - }, - .tSize = { - .iWidth = lv_area_get_width(coords), - .iHeight = lv_area_get_height(coords), - }, - }; - static arm_2d_tile_t source_tile; source_tile = (arm_2d_tile_t) { @@ -1132,45 +1266,81 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, .pchBuffer = (uint8_t *)src_buf, }; - static arm_2d_tile_t mask_tile; - mask_tile = source_tile; - - mask_tile.tInfo.bHasEnforcedColour = true; - mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32; - mask_tile.pchBuffer += 3; - static arm_2d_location_t source_center, target_center; source_center.iX = draw_dsc->pivot.x; source_center.iY = draw_dsc->pivot.y; - - if((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || + if((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || (LV_IMG_CF_TRUE_COLOR == cf)) { - arm_2d_tile_transform_with_opacity( + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_opacity_prepare, &source_tile, - &target_tile, - &target_region, source_center, ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), draw_dsc->zoom / 256.0f, (color_int)LV_COLOR_CHROMA_KEY.full, blend_dsc.opa); + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); + is_accelerated = true; + } + else if (LV_IMG_CF_RGB565A8 == cf) { + static arm_2d_tile_t mask_tile; + mask_tile = source_tile; + + mask_tile.tInfo.bHasEnforcedColour = true; + mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_COLOUR_GRAY8; + mask_tile.pchBuffer = mask_after_rgb; + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_src_mask_and_opacity_prepare, + &source_tile, + &mask_tile, + source_center, + ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), + draw_dsc->zoom / 256.0f, + blend_dsc.opa + ); + + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); + is_accelerated = true; } #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) \ && __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__ - else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && + else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && (LV_COLOR_DEPTH == 32)) { - arm_2d_tile_transform_with_src_mask_and_opacity( + static arm_2d_tile_t mask_tile; + mask_tile = source_tile; + + mask_tile.tInfo.bHasEnforcedColour = true; + mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32; + mask_tile.pchBuffer += 3; + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_src_mask_and_opacity_prepare, &source_tile, &mask_tile, - &target_tile, - &target_region, source_center, ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), draw_dsc->zoom / 256.0f, - blend_dsc.opa); + blend_dsc.opa + ); + + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); is_accelerated = true; } @@ -1208,7 +1378,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, (color_int)draw_dsc->recolor.full, draw_dsc->recolor_opa); } -#if LV_DRAW_COMPLEX +#if LV_USE_DRAW_MASKS /*Apply the masks if any*/ if(mask_any) { lv_coord_t y; @@ -1275,7 +1445,7 @@ static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coo if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { uint32_t px_cnt = lv_area_get_size(dest_area); - lv_memset_ff(abuf, px_cnt); + lv_memset(abuf, 0xff, px_cnt); src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t); uint32_t dest_w = lv_area_get_width(dest_area); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h index 80b62e9f0..ffe1d4e27 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h @@ -72,6 +72,7 @@ typedef struct _lv_draw_ctx_t { */ const lv_area_t * clip_area; + void (*init_buf)(struct _lv_draw_ctx_t * draw_ctx); void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c index 41dc0f039..1deb39e0c 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c @@ -69,18 +69,19 @@ void lv_draw_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const if(dsc->opa <= LV_OPA_MIN) return; - lv_res_t res; + lv_res_t res = LV_RES_INV; + if(draw_ctx->draw_img) { res = draw_ctx->draw_img(draw_ctx, dsc, coords, src); } - else { + + if(res != LV_RES_OK) { res = decode_and_draw(draw_ctx, dsc, coords, src); } - if(res == LV_RES_INV) { + if(res != LV_RES_OK) { LV_LOG_WARN("Image draw error"); show_error(draw_ctx, coords, "No\ndata"); - return; } } diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk index 17371ac98..18a751eab 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk @@ -1,5 +1,3 @@ -CSRCS += lv_gpu_nxp.c - DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c deleted file mode 100644 index 46da9334a..000000000 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c +++ /dev/null @@ -1,418 +0,0 @@ -/** - * @file lv_gpu_nxp.c - * - */ - -/** - * MIT License - * - * Copyright 2022 NXP - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next paragraph) - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_gpu_nxp.h" - -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - -/* - * allow to use both PXP and VGLITE - - * both 2D accelerators can be used at the same time: - * thus VGLITE can be used to accelerate widget drawing - * while PXP accelerates Blit & Fill operations. - */ -#if LV_USE_GPU_NXP_PXP - #include "pxp/lv_draw_pxp_blend.h" -#endif -#if LV_USE_GPU_NXP_VG_LITE - #include "vglite/lv_draw_vglite_blend.h" - #include "vglite/lv_draw_vglite_rect.h" - #include "vglite/lv_draw_vglite_arc.h" -#endif - -#if LV_COLOR_DEPTH != 32 - #include "../../core/lv_refr.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); - -static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); - -static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); - -static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); - -static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - uint16_t radius, uint16_t start_angle, uint16_t end_angle); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_draw_nxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) -{ - lv_draw_sw_init_ctx(drv, draw_ctx); - - lv_draw_nxp_ctx_t * nxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; - - nxp_draw_ctx->base_draw.draw_arc = lv_draw_nxp_arc; - nxp_draw_ctx->base_draw.draw_rect = lv_draw_nxp_rect; - nxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_nxp_img_decoded; - nxp_draw_ctx->blend = lv_draw_nxp_blend; - //nxp_draw_ctx->base_draw.wait_for_finish = lv_draw_nxp_wait_cb; -} - -void lv_draw_nxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) -{ - lv_draw_sw_deinit_ctx(drv, draw_ctx); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * During rendering, LVGL might initializes new draw_ctxs and start drawing into - * a separate buffer (called layer). If the content to be rendered has "holes", - * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. - * It means the renderers should draw into an ARGB buffer. - * With 32 bit color depth it's not a big problem but with 16 bit color depth - * the target pixel format is ARGB8565 which is not supported by the GPU. - * In this case, the NXP callbacks should fallback to SW rendering. - */ -static inline bool need_argb8565_support() -{ -#if LV_COLOR_DEPTH != 32 - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - - if(disp->driver->screen_transp == 1) - return true; -#endif - - return false; -} - -static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) -{ - lv_area_t blend_area; - - /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/ - if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) - return; /*Fully clipped, nothing to do*/ - - /*Make the blend area relative to the buffer*/ - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - bool done = false; - - /*Fill/Blend only non masked, normal blended*/ - if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && !need_argb8565_support()) { - lv_color_t * dest_buf = draw_ctx->buf; - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); -#if LV_USE_GPU_NXP_VG_LITE - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); -#endif - - const lv_color_t * src_buf = dsc->src_buf; - - if(src_buf == NULL) { -#if LV_USE_GPU_NXP_PXP - done = (lv_gpu_nxp_pxp_fill(dest_buf, dest_stride, &blend_area, - dsc->color, dsc->opa) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP fill failed. Fallback."); - -#endif -#if LV_USE_GPU_NXP_VG_LITE - if(!done) { - done = (lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &blend_area, - dsc->color, dsc->opa) == LV_RES_OK); - if(!done) - VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback."); - } -#endif - } - else { -#if LV_USE_GPU_NXP_PXP - done = (lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, dsc->blend_area, - dsc->opa, LV_DISP_ROT_NONE) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP blit failed. Fallback."); -#endif -#if LV_USE_GPU_NXP_VG_LITE - if(!done) { - lv_gpu_nxp_vglite_blit_info_t blit; - lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); - - blit.src = src_buf; - blit.src_width = lv_area_get_width(dsc->blend_area); - blit.src_height = lv_area_get_height(dsc->blend_area); - blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t); - blit.src_area.x1 = (blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1)); - blit.src_area.y1 = (blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1; - blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1; - - blit.dst = dest_buf; - blit.dst_width = dest_width; - blit.dst_height = dest_height; - blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t); - blit.dst_area.x1 = blend_area.x1; - blit.dst_area.y1 = blend_area.y1; - blit.dst_area.x2 = blend_area.x2; - blit.dst_area.y2 = blend_area.y2; - - blit.opa = dsc->opa; - blit.zoom = LV_IMG_ZOOM_NONE; - blit.angle = 0; - - done = (lv_gpu_nxp_vglite_blit(&blit) == LV_RES_OK); - - if(!done) - VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback."); - } -#endif - } - } - - if(!done) - lv_draw_sw_blend_basic(draw_ctx, dsc); -} - -static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) -{ - /*Use the clip area as draw area*/ - lv_area_t draw_area; - lv_area_copy(&draw_area, draw_ctx->clip_area); - bool mask_any = lv_draw_mask_is_any(&draw_area); -#if LV_USE_GPU_NXP_VG_LITE - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); -#endif -#if LV_USE_GPU_NXP_PXP - bool scale = (dsc->zoom != LV_IMG_ZOOM_NONE); -#endif - bool done = false; - - lv_area_t blend_area; - /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/ - if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) - return; /*Fully clipped, nothing to do*/ - - /*Make the blend area relative to the buffer*/ - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - const lv_color_t * src_buf = (const lv_color_t *)map_p; - if(!src_buf) { - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); - return; - } - - lv_color_t * dest_buf = draw_ctx->buf; - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); - -#if LV_USE_GPU_NXP_PXP - if(!mask_any && !scale && !need_argb8565_support() -#if LV_COLOR_DEPTH!=32 - && !lv_img_cf_has_alpha(cf) -#endif - ) { - done = (lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, coords, - dsc, cf) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP blit transform failed. Fallback."); - } -#endif - -#if LV_USE_GPU_NXP_VG_LITE - if(!done && !mask_any && !need_argb8565_support() && - !lv_img_cf_is_chroma_keyed(cf) && !recolor -#if LV_COLOR_DEPTH!=32 - && !lv_img_cf_has_alpha(cf) -#endif - ) { - lv_gpu_nxp_vglite_blit_info_t blit; - lv_coord_t src_stride = lv_area_get_width(coords); - - blit.src = src_buf; - blit.src_width = lv_area_get_width(coords); - blit.src_height = lv_area_get_height(coords); - blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t); - blit.src_area.x1 = (blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1)); - blit.src_area.y1 = (blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1; - blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1; - - blit.dst = dest_buf; - blit.dst_width = lv_area_get_width(draw_ctx->buf_area); - blit.dst_height = lv_area_get_height(draw_ctx->buf_area); - blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t); - blit.dst_area.x1 = blend_area.x1; - blit.dst_area.y1 = blend_area.y1; - blit.dst_area.x2 = blend_area.x2; - blit.dst_area.y2 = blend_area.y2; - - blit.opa = dsc->opa; - blit.angle = dsc->angle; - blit.pivot = dsc->pivot; - blit.zoom = dsc->zoom; - - done = (lv_gpu_nxp_vglite_blit_transform(&blit) == LV_RES_OK); - - if(!done) - VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback."); - } -#endif - - if(!done) - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); -} - -static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) -{ - bool done = false; - lv_draw_rect_dsc_t nxp_dsc; - - lv_memcpy(&nxp_dsc, dsc, sizeof(nxp_dsc)); -#if LV_DRAW_COMPLEX - /* Draw only the shadow */ - nxp_dsc.bg_opa = 0; - nxp_dsc.bg_img_opa = 0; - nxp_dsc.border_opa = 0; - nxp_dsc.outline_opa = 0; - - lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords); - - /* Draw the background */ - nxp_dsc.shadow_opa = 0; - nxp_dsc.bg_opa = dsc->bg_opa; - done = (draw_nxp_bg(draw_ctx, &nxp_dsc, coords) == LV_RES_OK); -#endif /*LV_DRAW_COMPLEX*/ - - /* Draw the remaining parts */ - nxp_dsc.shadow_opa = 0; - if(done) - nxp_dsc.bg_opa = 0; - nxp_dsc.bg_img_opa = dsc->bg_img_opa; - nxp_dsc.border_opa = dsc->border_opa; - nxp_dsc.outline_opa = dsc->outline_opa; - - lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords); -} - -static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) -{ - if(dsc->bg_opa <= LV_OPA_MIN) - return LV_RES_INV; - - lv_area_t bg_coords; - lv_area_copy(&bg_coords, coords); - - /*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) { - bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; - bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; - bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; - bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; - } - - lv_area_t clipped_coords; - if(!_lv_area_intersect(&clipped_coords, &bg_coords, draw_ctx->clip_area)) - return LV_RES_INV; - - lv_grad_dir_t grad_dir = dsc->bg_grad.dir; - lv_color_t bg_color = grad_dir == LV_GRAD_DIR_NONE ? dsc->bg_color : dsc->bg_grad.stops[0].color; - if(bg_color.full == dsc->bg_grad.stops[1].color.full) grad_dir = LV_GRAD_DIR_NONE; - - bool mask_any = lv_draw_mask_is_any(&bg_coords); - - /* - * Most simple case: just a plain rectangle (no mask, no radius, no gradient) - * shall fallback to lv_draw_sw_blend(). - * - * Complex case: gradient or radius but no mask. - */ - if(!mask_any && ((dsc->radius != 0) || (grad_dir != LV_GRAD_DIR_NONE)) && !need_argb8565_support()) { -#if LV_USE_GPU_NXP_VG_LITE - lv_res_t res = lv_gpu_nxp_vglite_draw_bg(draw_ctx, dsc, &bg_coords); - if(res != LV_RES_OK) - VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback."); - - return res; -#endif - } - - return LV_RES_INV; -} - -static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - uint16_t radius, uint16_t start_angle, uint16_t end_angle) -{ - bool done = false; - -#if LV_DRAW_COMPLEX - if(dsc->opa <= LV_OPA_MIN) - return; - if(dsc->width == 0) - return; - if(start_angle == end_angle) - return; - -#if LV_USE_GPU_NXP_VG_LITE - if(!need_argb8565_support()) { - done = (lv_gpu_nxp_vglite_draw_arc(draw_ctx, dsc, center, (int32_t)radius, - (int32_t)start_angle, (int32_t)end_angle) == LV_RES_OK); - if(!done) - VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback."); - } -#endif -#endif/*LV_DRAW_COMPLEX*/ - - if(!done) - lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); -} - -#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk index ff475a193..5c684bcd5 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk @@ -1,3 +1,4 @@ +CSRCS += lv_draw_pxp.c CSRCS += lv_draw_pxp_blend.c CSRCS += lv_gpu_nxp_pxp_osa.c CSRCS += lv_gpu_nxp_pxp.c diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c new file mode 100644 index 000000000..a7084b408 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c @@ -0,0 +1,250 @@ +/** + * @file lv_draw_pxp.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_pxp.h" + +#if LV_USE_GPU_NXP_PXP +#include "lv_draw_pxp_blend.h" + +#if LV_COLOR_DEPTH != 32 + #include "../../../core/lv_refr.h" +#endif + +/********************* + * DEFINES + *********************/ + +/* Minimum area (in pixels) for PXP blit/fill processing. */ +#ifndef LV_GPU_NXP_PXP_SIZE_LIMIT + #define LV_GPU_NXP_PXP_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); + +static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_pxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_init_ctx(drv, draw_ctx); + + lv_draw_pxp_ctx_t * pxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; + 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; +} + +void lv_draw_pxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_deinit_ctx(drv, draw_ctx); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * During rendering, LVGL might initializes new draw_ctxs and start drawing into + * a separate buffer (called layer). If the content to be rendered has "holes", + * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. + * It means the renderers should draw into an ARGB buffer. + * With 32 bit color depth it's not a big problem but with 16 bit color depth + * the target pixel format is ARGB8565 which is not supported by the GPU. + * In this case, the PXP callbacks should fallback to SW rendering. + */ +static inline bool need_argb8565_support() +{ +#if LV_COLOR_DEPTH != 32 + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + + if(disp->driver->screen_transp == 1) + return true; +#endif + + return false; +} + +static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx) +{ + lv_gpu_nxp_pxp_wait(); + + lv_draw_sw_wait_for_finish(draw_ctx); +} + +static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + if(dsc->mask_buf != NULL || dsc->blend_mode != LV_BLEND_MODE_NORMAL || + lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + /*Fill/Blend only non masked, normal blended*/ + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + const lv_color_t * src_buf = dsc->src_buf; + + if(src_buf == NULL) { + lv_gpu_nxp_pxp_fill(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa); + } + else { + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1; + src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1; + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + + lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride, + dsc->opa, LV_DISP_ROT_NONE); + } +} + +static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + const lv_color_t * src_buf = (const lv_color_t *)map_p; + if(!src_buf) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area.*/ + if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_coord_t src_width = lv_area_get_width(coords); + lv_coord_t src_height = lv_area_get_height(coords); + + bool has_mask = lv_draw_mask_is_any(&blend_area); + bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE); + bool has_rotation = (dsc->angle != 0); + bool unsup_rotation = false; + + if(has_rotation) { + /* + * PXP can only rotate at 90x angles. + */ + if(dsc->angle % 900) { + PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); + unsup_rotation = true; + } + + /* + * 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. + */ + if(src_width % 16 || src_height % 16) { + PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16."); + unsup_rotation = true; + } + } + + if(has_mask || has_scale || unsup_rotation || lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT +#if LV_COLOR_DEPTH != 32 + || lv_img_cf_has_alpha(cf) +#endif + ) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + src_width - 1; + src_area.y2 = src_area.y1 + src_height - 1; + lv_coord_t src_stride = lv_area_get_width(coords); + + lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride, + dsc, cf); +} + +#endif /*LV_USE_GPU_NXP_PXP*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h similarity index 77% rename from lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h rename to lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h index 899aff25b..1ace3bca4 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h @@ -1,12 +1,12 @@ /** - * @file lv_gpu_nxp.h + * @file lv_draw_pxp.h * */ /** * MIT License * - * Copyright 2022 NXP + * Copyright 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,8 +27,8 @@ * */ -#ifndef LV_GPU_NXP_H -#define LV_GPU_NXP_H +#ifndef LV_DRAW_PXP_H +#define LV_DRAW_PXP_H #ifdef __cplusplus extern "C" { @@ -38,9 +38,10 @@ extern "C" { * INCLUDES *********************/ -#include "../../lv_conf_internal.h" -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE -#include "../sw/lv_draw_sw.h" +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP +#include "../../sw/lv_draw_sw.h" /********************* * DEFINES @@ -49,23 +50,23 @@ extern "C" { /********************** * TYPEDEFS **********************/ -typedef lv_draw_sw_ctx_t lv_draw_nxp_ctx_t; +typedef lv_draw_sw_ctx_t lv_draw_pxp_ctx_t; /********************** * GLOBAL PROTOTYPES **********************/ -void lv_draw_nxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_pxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); -void lv_draw_nxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_pxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); /********************** * MACROS **********************/ -#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ +#endif /*LV_USE_GPU_NXP_PXP*/ #ifdef __cplusplus } /*extern "C"*/ #endif -#endif /*LV_GPU_NXP_H*/ +#endif /*LV_DRAW_PXP_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c index c0a6ecafa..a32c91710 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,20 +34,23 @@ #include "lv_draw_pxp_blend.h" #if LV_USE_GPU_NXP_PXP +#include "lvgl_support.h" /********************* * DEFINES *********************/ +#define PXP_TEMP_BUF_SIZE LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL + #if LV_COLOR_16_SWAP #error Color swap not implemented. Disable LV_COLOR_16_SWAP feature. #endif -#if LV_COLOR_DEPTH==16 +#if LV_COLOR_DEPTH == 16 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565 -#elif LV_COLOR_DEPTH==32 +#elif LV_COLOR_DEPTH == 32 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888 @@ -55,13 +58,6 @@ #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. #endif -#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \ - || defined (_WIN64) || defined (__LP64__) || defined (__LLP64__) - #define ALIGN_SIZE 8 -#else - #define ALIGN_SIZE 4 -#endif - /********************** * TYPEDEFS **********************/ @@ -70,63 +66,60 @@ * STATIC PROTOTYPES **********************/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t temp_buf[PXP_TEMP_BUF_SIZE]; + /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * with combination of transformation (rotation, scale, recolor) and opacity, alpha channel * or color keying. This requires two steps. First step is used for transformation into * a temporary buffer and the second one will handle the color format or opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * with transformation and full opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * without transformation but handling color format or opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /********************** * STATIC VARIABLES @@ -136,45 +129,27 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * * MACROS **********************/ -#define ROUND_UP(x, align) ((x + (align - 1)) & ~(align - 1)) - /********************** * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa) +void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa) { - uint32_t area_size = lv_area_get_size(fill_area); - lv_coord_t area_w = lv_area_get_width(fill_area); - lv_coord_t area_h = lv_area_get_height(fill_area); + lv_coord_t dest_w = lv_area_get_width(dest_area); + lv_coord_t dest_h = lv_area_get_height(dest_area); - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(area_size < LV_GPU_NXP_PXP_FILL_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_SIZE_LIMIT); - return LV_RES_INV; - } - } - else { - if(area_size < LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); /*OUT buffer configure*/ pxp_output_buffer_config_t outputConfig = { .pixelFormat = PXP_OUT_PIXEL_FORMAT, .interlacedMode = kPXP_OutputProgressive, - .buffer0Addr = (uint32_t)(dest_buf + dest_stride * fill_area->y1 + fill_area->x1), + .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1), .buffer1Addr = (uint32_t)NULL, .pitchBytes = dest_stride * sizeof(lv_color_t), - .width = area_w, - .height = area_h + .width = dest_w, + .height = dest_h }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig); @@ -193,7 +168,7 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, area_w, area_h); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } /*Disable PS, use as color generator*/ @@ -223,34 +198,19 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); - lv_gpu_nxp_pxp_run(); /*Start PXP task*/ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle) +void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa, lv_disp_rot_t angle) { - uint32_t dest_size = lv_area_get_size(dest_area); lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT); - return LV_RES_INV; - } - } - else { - if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); /* convert rotation angle */ pxp_rotate_degree_t pxp_rot; @@ -297,19 +257,17 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, asBlendConfig.alphaMode = kPXP_AlphaOverride; PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); - PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); + PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false); @@ -325,162 +283,102 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_pxp_run(); /* Start PXP task */ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { - uint32_t dest_size = lv_area_get_size(dest_area); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_rotation = (dsc->angle != 0); - if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT); - return LV_RES_INV; + if(has_recolor || has_rotation) { + if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) { + lv_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); + return; } - } - else { - if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - bool rotation = (dsc->angle != 0); - - if(rotation) { - if(dsc->angle != 0 && dsc->angle != 900 && dsc->angle != 1800 && dsc->angle != 2700) { - PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); - return LV_RES_INV; - } - } - - if(recolor || rotation) { - if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) - return lv_gpu_nxp_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); - else + else { /*Recolor and/or rotation with alpha or opacity is done in two steps.*/ - return lv_gpu_nxp_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); + lv_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); + return; + } } - return lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); + lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); } /********************** * STATIC FUNCTIONS **********************/ -static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { - lv_coord_t dest_w = lv_area_get_width(dest_area); - lv_coord_t dest_h = lv_area_get_height(dest_area); - lv_res_t res; - uint32_t size = dest_w * dest_h * sizeof(lv_color_t); - - if(ROUND_UP(size, ALIGN_SIZE) >= LV_MEM_SIZE) - PXP_RETURN_INV("Insufficient memory for temporary buffer. Please increase LV_MEM_SIZE."); - - lv_color_t * tmp_buf = (lv_color_t *)lv_mem_buf_get(size); - if(!tmp_buf) - PXP_RETURN_INV("Allocating temporary buffer failed."); - - const lv_area_t tmp_area = { + lv_coord_t temp_area_w = lv_area_get_width(dest_area); + lv_coord_t temp_area_h = lv_area_get_height(dest_area); + const lv_area_t temp_area = { .x1 = 0, .y1 = 0, - .x2 = dest_w - 1, - .y2 = dest_h - 1 + .x2 = temp_area_w - 1, + .y2 = temp_area_h - 1 }; /*Step 1: Transform with full opacity to temporary buffer*/ - res = lv_gpu_nxp_pxp_blit_cover(tmp_buf, &tmp_area, dest_w, src_buf, src_area, dsc, cf); - if(res != LV_RES_OK) { - PXP_LOG_TRACE("Blit cover with full opacity failed."); - lv_mem_buf_release(tmp_buf); + lv_pxp_blit_cover((lv_color_t *)temp_buf, &temp_area, temp_area_w, src_buf, src_area, src_stride, dsc, cf); - return res; - } - - /*Step 2: Blit temporary results with required opacity to output*/ - res = lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, tmp_buf, &tmp_area, dsc, cf); - - /*Clean-up memory*/ - lv_mem_buf_release(tmp_buf); - - return res; + /*Step 2: Blit temporary result with required opacity to output*/ + lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, (lv_color_t *)temp_buf, &temp_area, temp_area_w, dsc, cf); } - -static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - bool rotation = (dsc->angle != 0); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_rotation = (dsc->angle != 0); - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ - - if(rotation) { - /* - * 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. - */ - if(lv_area_get_width(src_area) % 16 || lv_area_get_height(src_area) % 16) { - PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16."); - return LV_RES_INV; - } + lv_gpu_nxp_pxp_reset(); + if(has_rotation) { /*Convert rotation angle*/ - pxp_rotate_degree_t pxp_rot; + pxp_rotate_degree_t pxp_angle; switch(dsc->angle) { case 0: - pxp_rot = kPXP_Rotate0; + pxp_angle = kPXP_Rotate0; break; case 900: - pxp_rot = kPXP_Rotate90; + pxp_angle = kPXP_Rotate90; break; case 1800: - pxp_rot = kPXP_Rotate180; + pxp_angle = kPXP_Rotate180; break; case 2700: - pxp_rot = kPXP_Rotate270; + pxp_angle = kPXP_Rotate270; break; default: - PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); - return LV_RES_INV; + pxp_angle = kPXP_Rotate0; } - PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable); + PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); /*Disable PS buffer*/ PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); - if(recolor) + if(has_recolor) /*Use as color generator*/ PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor)); @@ -496,7 +394,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - if(recolor || lv_img_cf_has_alpha(cf)) { + if(has_recolor || lv_img_cf_has_alpha(cf)) { /** * Configure Porter-Duff blending. * @@ -512,7 +410,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t .srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha, .dstFactorMode = kPXP_PorterDuffFactorStraight, .srcFactorMode = kPXP_PorterDuffFactorInversed, - .dstGlobalAlpha = recolor ? dsc->recolor_opa : 0x00, + .dstGlobalAlpha = has_recolor ? dsc->recolor_opa : 0x00, .srcGlobalAlpha = 0xff, .dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/ .srcAlphaMode = kPXP_PorterDuffAlphaStraight @@ -520,22 +418,19 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); } - lv_gpu_nxp_pxp_run(); /*Start PXP task*/ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); pxp_as_blend_config_t asBlendConfig = { .alpha = dsc->opa, @@ -566,28 +461,26 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride; } PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); - PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); + PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); if(lv_img_cf_is_chroma_keyed(cf)) { lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY; lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY; - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - if(recolor) { + if(has_recolor) { /* New color key after recoloring */ lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa); @@ -595,11 +488,11 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * LV_COLOR_SET_G(colorKeyLow, colorKey.ch.green != 0 ? colorKey.ch.green - 1 : 0); LV_COLOR_SET_B(colorKeyLow, colorKey.ch.blue != 0 ? colorKey.ch.blue - 1 : 0); -#if LV_COLOR_DEPTH==16 +#if LV_COLOR_DEPTH == 16 LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f); -#else /*LV_COLOR_DEPTH==32*/ +#else /*LV_COLOR_DEPTH == 32*/ LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff); @@ -624,9 +517,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_pxp_run(); /* Start PXP task */ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } #endif /*LV_USE_GPU_NXP_PXP*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h index 43a6440de..9fe9192f7 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -48,31 +48,6 @@ extern "C" { * DEFINES *********************/ -#ifndef LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with 100% opacity to be handled by PXP*/ -#define LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with transparency to be handled by PXP*/ -#define LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT -/** Minimum invalidated area (in pixels) to be synchronized by PXP during buffer sync */ -#define LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_FILL_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by PXP with 100% opacity*/ -#define LV_GPU_NXP_PXP_FILL_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by PXP with transparency*/ -#define LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT 5000 -#endif - /********************** * TYPEDEFS **********************/ @@ -84,51 +59,49 @@ extern "C" { /** * Fill area, with optional opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] fill_area area to fill - * @param[in] color color - * @param[in] opa transparency of the color - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] color Color + * @param[in] opa Opacity */ -lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa); +void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa); /** * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. * By default, image is copied directly, with optional opacity. This function can also * rotate the display output buffer to a specified angle (90x step). * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area destination area - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] opa opacity of the result - * @param[in] angle display rotation angle (90x) - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity + * @param[in] angle Display rotation angle (90x) */ -lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle); +void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa, lv_disp_rot_t angle); /** * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. * * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area destination area - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c index 94d242a0d..164216f44 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -50,9 +50,9 @@ **********************/ /** - * Clean & invalidate cache. + * Clean and invalidate cache. */ -static void invalidate_cache(void); +static inline void invalidate_cache(void); /********************** * STATIC VARIABLES @@ -70,16 +70,23 @@ static lv_nxp_pxp_cfg_t * pxp_cfg; lv_res_t lv_gpu_nxp_pxp_init(void) { +#if LV_USE_GPU_NXP_PXP_AUTO_INIT pxp_cfg = lv_gpu_nxp_pxp_get_cfg(); +#endif - if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init || !pxp_cfg->pxp_run) + if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init || + !pxp_cfg->pxp_run || !pxp_cfg->pxp_wait) PXP_RETURN_INV("PXP configuration error."); PXP_Init(LV_GPU_NXP_PXP_ID); + PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ + PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ + PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); if(pxp_cfg->pxp_interrupt_init() != LV_RES_OK) { + PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Deinit(LV_GPU_NXP_PXP_ID); PXP_RETURN_INV("PXP interrupt init failed."); } @@ -90,23 +97,38 @@ lv_res_t lv_gpu_nxp_pxp_init(void) void lv_gpu_nxp_pxp_deinit(void) { pxp_cfg->pxp_interrupt_deinit(); - PXP_DisableInterrupts(PXP, kPXP_CompleteInterruptEnable); + PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Deinit(LV_GPU_NXP_PXP_ID); } +void lv_gpu_nxp_pxp_reset(void) +{ + /* Wait for previous command to complete before resetting the registers. */ + lv_gpu_nxp_pxp_wait(); + + PXP_ResetControl(LV_GPU_NXP_PXP_ID); + + PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ + PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ +} + void lv_gpu_nxp_pxp_run(void) { - /*Clean & invalidate cache*/ invalidate_cache(); pxp_cfg->pxp_run(); } +void lv_gpu_nxp_pxp_wait(void) +{ + pxp_cfg->pxp_wait(); +} + /********************** * STATIC FUNCTIONS **********************/ -static void invalidate_cache(void) +static inline void invalidate_cache(void) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); if(disp->driver->clean_dcache_cb) diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h index e695d8f13..10a67215a 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -81,8 +81,11 @@ typedef struct { /** Callback for PXP interrupt de-initialization*/ void (*pxp_interrupt_deinit)(void); - /** Callback that should start PXP and wait for operation complete*/ + /** Callback for PXP start*/ void (*pxp_run)(void); + + /** Callback for waiting of PXP completion*/ + void (*pxp_wait)(void); } lv_nxp_pxp_cfg_t; /********************** @@ -104,10 +107,20 @@ lv_res_t lv_gpu_nxp_pxp_init(void); void lv_gpu_nxp_pxp_deinit(void); /** - * Start PXP job and wait for completion. + * Reset PXP device. + */ +void lv_gpu_nxp_pxp_reset(void); + +/** + * Clear cache and start PXP. */ void lv_gpu_nxp_pxp_run(void); +/** + * Wait for PXP completion. + */ +void lv_gpu_nxp_pxp_wait(void); + /********************** * MACROS **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c index c4b8dbe57..8e1884036 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020, 2022 NXP + * Copyright 2020, 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,24 +65,29 @@ static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void); static void _lv_gpu_nxp_pxp_interrupt_deinit(void); /** - * Start the PXP job and wait for task completion. + * Start the PXP job. */ static void _lv_gpu_nxp_pxp_run(void); +/** + * Wait for PXP completion. + */ +static void _lv_gpu_nxp_pxp_wait(void); + /********************** * STATIC VARIABLES **********************/ #if defined(SDK_OS_FREE_RTOS) - static SemaphoreHandle_t s_pxpIdle; -#else - static volatile bool s_pxpIdle; + static SemaphoreHandle_t s_pxpIdleSem; #endif +static volatile bool s_pxpIdle; static lv_nxp_pxp_cfg_t pxp_default_cfg = { .pxp_interrupt_init = _lv_gpu_nxp_pxp_interrupt_init, .pxp_interrupt_deinit = _lv_gpu_nxp_pxp_interrupt_deinit, - .pxp_run = _lv_gpu_nxp_pxp_run + .pxp_run = _lv_gpu_nxp_pxp_run, + .pxp_wait = _lv_gpu_nxp_pxp_wait, }; /********************** @@ -102,7 +107,7 @@ void PXP_IRQHandler(void) if(kPXP_CompleteFlag & PXP_GetStatusFlags(LV_GPU_NXP_PXP_ID)) { PXP_ClearStatusFlags(LV_GPU_NXP_PXP_ID, kPXP_CompleteFlag); #if defined(SDK_OS_FREE_RTOS) - xSemaphoreGiveFromISR(s_pxpIdle, &taskAwake); + xSemaphoreGiveFromISR(s_pxpIdleSem, &taskAwake); portYIELD_FROM_ISR(taskAwake); #else s_pxpIdle = true; @@ -122,14 +127,13 @@ lv_nxp_pxp_cfg_t * lv_gpu_nxp_pxp_get_cfg(void) static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) { #if defined(SDK_OS_FREE_RTOS) - s_pxpIdle = xSemaphoreCreateBinary(); - if(s_pxpIdle == NULL) + s_pxpIdleSem = xSemaphoreCreateBinary(); + if(s_pxpIdleSem == NULL) return LV_RES_INV; NVIC_SetPriority(LV_GPU_NXP_PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1); -#else - s_pxpIdle = true; #endif + s_pxpIdle = true; NVIC_EnableIRQ(LV_GPU_NXP_PXP_IRQ_ID); @@ -140,21 +144,33 @@ static void _lv_gpu_nxp_pxp_interrupt_deinit(void) { NVIC_DisableIRQ(LV_GPU_NXP_PXP_IRQ_ID); #if defined(SDK_OS_FREE_RTOS) - vSemaphoreDelete(s_pxpIdle); + vSemaphoreDelete(s_pxpIdleSem); #endif } +/** + * Function to start PXP job. + */ static void _lv_gpu_nxp_pxp_run(void) { -#if !defined(SDK_OS_FREE_RTOS) s_pxpIdle = false; -#endif PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Start(LV_GPU_NXP_PXP_ID); +} +/** + * Function to wait for PXP completion. + */ +static void _lv_gpu_nxp_pxp_wait(void) +{ #if defined(SDK_OS_FREE_RTOS) - PXP_COND_STOP(!xSemaphoreTake(s_pxpIdle, portMAX_DELAY), "xSemaphoreTake failed."); + /* Return if PXP was never started, otherwise the semaphore will lock forever. */ + if(s_pxpIdle == true) + return; + + if(xSemaphoreTake(s_pxpIdleSem, portMAX_DELAY) == pdTRUE) + s_pxpIdle = true; #else while(s_pxpIdle == false) { } diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk index c84e2e47a..c9473cc10 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk @@ -1,7 +1,10 @@ +CSRCS += lv_draw_vglite.c CSRCS += lv_draw_vglite_arc.c CSRCS += lv_draw_vglite_blend.c +CSRCS += lv_draw_vglite_line.c CSRCS += lv_draw_vglite_rect.c -CSRCS += lv_gpu_nxp_vglite.c +CSRCS += lv_vglite_buf.c +CSRCS += lv_vglite_utils.c DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp/vglite VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp/vglite diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c new file mode 100644 index 000000000..eae1b8a58 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c @@ -0,0 +1,508 @@ +/** + * @file lv_draw_vglite.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_vglite.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include +#include "lv_draw_vglite_blend.h" +#include "lv_draw_vglite_line.h" +#include "lv_draw_vglite_rect.h" +#include "lv_draw_vglite_arc.h" +#include "lv_vglite_buf.h" + +#if LV_COLOR_DEPTH != 32 + #include "../../../core/lv_refr.h" +#endif + +/********************* + * DEFINES + *********************/ + +/* Minimum area (in pixels) for VG-Lite blit/fill processing. */ +#ifndef LV_GPU_NXP_VG_LITE_SIZE_LIMIT + #define LV_GPU_NXP_VG_LITE_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); + +static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + +static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords); + +static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_vglite_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_init_ctx(drv, draw_ctx); + + lv_draw_vglite_ctx_t * vglite_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; + 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; +} + +void lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_deinit_ctx(drv, draw_ctx); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * During rendering, LVGL might initializes new draw_ctxs and start drawing into + * a separate buffer (called layer). If the content to be rendered has "holes", + * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. + * It means the renderers should draw into an ARGB buffer. + * With 32 bit color depth it's not a big problem but with 16 bit color depth + * the target pixel format is ARGB8565 which is not supported by the GPU. + * In this case, the VG-Lite callbacks should fallback to SW rendering. + */ +static inline bool need_argb8565_support() +{ +#if LV_COLOR_DEPTH != 32 + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + + if(disp->driver->screen_transp == 1) + return true; +#endif + + return false; +} + +static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx) +{ + lv_gpu_nxp_vglite_init_buf(draw_ctx->buf, draw_ctx->buf_area, lv_area_get_width(draw_ctx->buf_area)); +} + +static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx) +{ + vg_lite_finish(); + + lv_draw_sw_wait_for_finish(draw_ctx); +} + +static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + bool done = false; + /*Fill/Blend only non masked, normal blended*/ + if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && + lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) { + const lv_color_t * src_buf = dsc->src_buf; + + if(src_buf == NULL) { + done = (lv_gpu_nxp_vglite_fill(&blend_area, dsc->color, dsc->opa) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback."); + } + else { + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1; + src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1; + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + + done = (lv_gpu_nxp_vglite_blit(dest_buf, &blend_area, dest_stride, + src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK); + + if(!done) + VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback."); + } + } + + if(!done) + lv_draw_sw_blend_basic(draw_ctx, dsc); +} + +static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + const lv_color_t * src_buf = (const lv_color_t *)map_p; + if(!src_buf) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + bool has_mask = lv_draw_mask_is_any(&blend_area); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + + bool done = false; + if(!has_mask && !has_recolor && !lv_img_cf_is_chroma_keyed(cf) && + lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT +#if LV_COLOR_DEPTH != 32 + && !lv_img_cf_has_alpha(cf) +#endif + ) { + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->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; + lv_coord_t src_stride = lv_area_get_width(coords); + + done = (lv_gpu_nxp_vglite_blit_transform(dest_buf, &blend_area, dest_stride, + src_buf, &src_area, src_stride, dsc) == LV_RES_OK); + + if(!done) + VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback."); + } + + if(!done) + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); +} + +static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2) +{ + if(dsc->width == 0) + return; + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + if(point1->x == point2->x && point1->y == point2->y) + return; + + if(need_argb8565_support()) { + lv_draw_sw_line(draw_ctx, dsc, point1, point2); + return; + } + + lv_area_t rel_clip_area; + rel_clip_area.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2; + rel_clip_area.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2; + rel_clip_area.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2; + rel_clip_area.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2; + + bool is_common; + is_common = _lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_ctx->clip_area); + if(!is_common) + return; + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_point_t rel_point1 = { point1->x - draw_ctx->buf_area->x1, point1->y - draw_ctx->buf_area->y1 }; + lv_point_t rel_point2 = { point2->x - draw_ctx->buf_area->x1, point2->y - draw_ctx->buf_area->y1 }; + + bool done = false; + bool mask_any = lv_draw_mask_is_any(&rel_clip_area); + + if(!mask_any) { + done = (lv_gpu_nxp_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite draw line failed. Fallback."); + } + + if(!done) + lv_draw_sw_line(draw_ctx, dsc, point1, point2); +} + +static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +{ + if(need_argb8565_support()) { + lv_draw_sw_rect(draw_ctx, dsc, coords); + return; + } + + lv_draw_rect_dsc_t vglite_dsc; + + lv_memcpy(&vglite_dsc, dsc, sizeof(vglite_dsc)); + vglite_dsc.bg_opa = 0; + vglite_dsc.bg_img_opa = 0; + vglite_dsc.border_opa = 0; + vglite_dsc.outline_opa = 0; +#if LV_DRAW_COMPLEX + /* Draw the shadow with CPU */ + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.shadow_opa = 0; +#endif /*LV_DRAW_COMPLEX*/ + + /* Draw the background */ + vglite_dsc.bg_opa = dsc->bg_opa; + if(lv_draw_vglite_bg(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.bg_opa = 0; + + /* Draw the background image + * It will be done once draw_ctx->draw_img_decoded() + * callback gets called from lv_draw_sw_rect(). + */ + vglite_dsc.bg_img_opa = dsc->bg_img_opa; + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.bg_img_opa = 0; + + /* Draw the border */ + vglite_dsc.border_opa = dsc->border_opa; + if(lv_draw_vglite_border(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.border_opa = 0; + + /* Draw the outline */ + vglite_dsc.outline_opa = dsc->outline_opa; + if(lv_draw_vglite_outline(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); +} + +static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +{ + if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + + lv_area_t rel_coords; + lv_area_copy(&rel_coords, coords); + + /*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; + } + + /* Make coordinates relative to draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area)) + return LV_RES_INV; + + bool mask_any = lv_draw_mask_is_any(&rel_coords); + lv_grad_dir_t grad_dir = dsc->bg_grad.dir; + lv_color_t bg_color = (grad_dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) ? + dsc->bg_color : dsc->bg_grad.stops[0].color; + if(bg_color.full == dsc->bg_grad.stops[1].color.full) + grad_dir = LV_GRAD_DIR_NONE; + + /* + * Most simple case: just a plain rectangle (no mask, no radius, no gradient) + * shall be handled by draw_ctx->blend(). + * + * Complex case: gradient or radius but no mask. + */ + if(!mask_any && ((dsc->radius != 0) || (grad_dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))) { + lv_res_t res = lv_gpu_nxp_vglite_draw_bg(&rel_coords, &rel_clip_area, dsc); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback."); + + return res; + } + + return LV_RES_INV; +} + +static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords) +{ + if(dsc->border_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + if(dsc->border_width == 0) + return LV_RES_INV; + if(dsc->border_post) + return LV_RES_INV; + if(dsc->border_side != (lv_border_side_t)LV_BORDER_SIDE_FULL) + return LV_RES_INV; + + lv_area_t rel_coords; + lv_coord_t border_width = dsc->border_width; + + /* Move border inwards to align with software rendered border */ + rel_coords.x1 = coords->x1 + ceil(border_width / 2.0f); + rel_coords.x2 = coords->x2 - floor(border_width / 2.0f); + rel_coords.y1 = coords->y1 + ceil(border_width / 2.0f); + rel_coords.y2 = coords->y2 - floor(border_width / 2.0f); + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, true); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw border failed. Fallback."); + + return res; +} + +static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords) +{ + if(dsc->outline_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + if(dsc->outline_width == 0) + return LV_RES_INV; + + /* Move outline outwards to align with software rendered outline */ + lv_coord_t outline_pad = dsc->outline_pad - 1; + lv_area_t rel_coords; + 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); + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, false); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw outline failed. Fallback."); + + return res; +} + +static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle) +{ + bool done = false; + +#if LV_DRAW_COMPLEX + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + if(dsc->width == 0) + return; + if(start_angle == end_angle) + return; + + if(need_argb8565_support()) { + lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); + return; + } + + /* Make coordinates relative to the draw buffer */ + lv_point_t rel_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1}; + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + done = (lv_gpu_nxp_vglite_draw_arc(&rel_center, (int32_t)radius, (int32_t)start_angle, (int32_t)end_angle, + &rel_clip_area, dsc) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback."); +#endif/*LV_DRAW_COMPLEX*/ + + if(!done) + lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h new file mode 100644 index 000000000..c44cb8fc7 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h @@ -0,0 +1,72 @@ +/** + * @file lv_draw_vglite.h + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_VGLITE_H +#define LV_DRAW_VGLITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "../../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_vglite_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_vglite_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_vglite_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c index 194f03d88..775bf734b 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,8 @@ #include "lv_draw_vglite_arc.h" #if LV_USE_GPU_NXP_VG_LITE -#include "math.h" +#include "lv_vglite_buf.h" +#include /********************* * DEFINES @@ -88,7 +89,7 @@ typedef struct _cubic_cont_pt { static void rotate_point(int32_t angle, int32_t * x, int32_t * y); static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, - int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw); + int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw); /********************** * STATIC VARIABLES @@ -102,31 +103,20 @@ static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - int32_t radius, int32_t start_angle, int32_t end_angle) +lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle, + const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc) { - - vg_lite_buffer_t vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; lv_color32_t col32 = {.full = lv_color_to32(dsc->color)}; /*Convert color to RGBA8888*/ - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); vg_lite_path_t path; vg_lite_color_t vgcol; /* vglite takes ABGR */ - vg_lite_matrix_t matrix; - lv_opa_t opa = dsc->opa; bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false; - lv_point_t clip_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1}; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); /* path: max size = 16 cubic bezier (7 words each) */ int32_t arc_path[16 * 7]; lv_memset_00(arc_path, sizeof(arc_path)); - /*** Init destination buffer ***/ - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - /*** Init path ***/ lv_coord_t width = dsc->width; /* inner arc radius = outer arc radius - width */ if(width > (lv_coord_t)radius) @@ -140,11 +130,11 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_MOVE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; /* draw 1-5 outer quarters */ - add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, clip_center, true); + add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, center, true); if(donut) { /* close outer circle */ @@ -152,24 +142,24 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; /* start inner circle */ cp_x = radius - width; cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_MOVE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } else if(dsc->rounded != 0U) { /* 1st rounded arc ending */ cp_x = radius - width / 2; cp_y = 0; rotate_point(end_angle, &cp_x, &cp_y); - lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; + lv_point_t round_center = {center->x + cp_x, center->y + cp_y}; add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180), - round_center, true); + &round_center, true); } else { /* 1st flat ending */ @@ -177,12 +167,12 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(end_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } /* draw 1-5 inner quarters */ - add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, clip_center, false); + add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, center, false); /* last control point of curve */ if(donut) { /* close the loop */ @@ -190,17 +180,17 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */ cp_x = radius - width / 2; cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); - lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; + lv_point_t round_center = {center->x + cp_x, center->y + cp_y}; add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360), - round_center, true); + &round_center, true); } else { /* 2nd flat ending */ @@ -208,46 +198,30 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } 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) draw_ctx->clip_area->x1, (vg_lite_float_t) draw_ctx->clip_area->y1, - ((vg_lite_float_t) draw_ctx->clip_area->x2) + 1.0f, ((vg_lite_float_t) draw_ctx->clip_area->y2) + 1.0f); + (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_ERR_RETURN_INV(err, "Init path failed."); - /* set rotation angle */ + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + vg_lite_matrix_t matrix; vg_lite_identity(&matrix); - if(opa <= (lv_opa_t)LV_OPA_MAX) { - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); - col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8); - col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8); - } - col32.ch.alpha = opa; - } - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - /*** Draw arc ***/ - err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); VG_LITE_ERR_RETURN_INV(err, "Draw arc failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -564,50 +538,50 @@ static void get_arc_control_points(vg_arc * arc, bool start) * center: (in) the center of the circle in draw coordinates * cw: (in) true if arc is clockwise */ -static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, lv_point_t center, bool cw) +static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, const lv_point_t * center, bool cw) { /* assumes first control point already in array arc_path[] */ int idx = *pidx; if(cw) { #if BEZIER_DBG_CONTROL_POINTS arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p3x + center.x; - arc_path[idx++] = q_arc->p3y + center.y; + arc_path[idx++] = q_arc->p3x + center->x; + arc_path[idx++] = q_arc->p3y + center->y; #else arc_path[idx++] = VLC_OP_CUBIC; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; - arc_path[idx++] = q_arc->p3x + center.x; - arc_path[idx++] = q_arc->p3y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; + arc_path[idx++] = q_arc->p3x + center->x; + arc_path[idx++] = q_arc->p3y + center->y; #endif } else { /* reverse points order when counter-clockwise */ #if BEZIER_DBG_CONTROL_POINTS arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p0x + center.x; - arc_path[idx++] = q_arc->p0y + center.y; + arc_path[idx++] = q_arc->p0x + center->x; + arc_path[idx++] = q_arc->p0y + center->y; #else arc_path[idx++] = VLC_OP_CUBIC; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; - arc_path[idx++] = q_arc->p0x + center.x; - arc_path[idx++] = q_arc->p0y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; + arc_path[idx++] = q_arc->p0x + center->x; + arc_path[idx++] = q_arc->p0y + center->y; #endif } /* update index i n path array*/ @@ -615,7 +589,7 @@ static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, l } static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, - int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw) + int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw) { /* set number of arcs to draw */ vg_arc q_arc; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h index 98ba8a3d0..0fbff3d92 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" /********************* * DEFINES @@ -54,17 +54,21 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -/*** +/** * Draw arc shape with effects - * @param draw_ctx drawing context - * @param dsc the arc description structure (width, rounded ending, opacity) - * @param center the coordinates of the arc center - * @param radius the radius of external arc - * @param start_angle the starting angle in degrees - * @param end_angle the ending angle in degrees + * + * @param[in] center Arc center with relative coordinates + * @param[in] radius Radius of external arc + * @param[in] start_angle Starting angle in degrees + * @param[in] end_angle Ending angle in degrees + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Arc description structure (width, rounded ending, opacity) + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - int32_t radius, int32_t start_angle, int32_t end_angle); +lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle, + const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c index b59b143b3..e1408b760 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,12 +34,19 @@ #include "lv_draw_vglite_blend.h" #if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" /********************* * DEFINES *********************/ -/* Enable BLIT quality degradation workaround for RT595, recommended for screen's dimension > 352 pixels */ +/** Stride in px required by VG-Lite HW*/ +#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U + +/** + * Enable BLIT quality degradation workaround for RT595, + * recommended for screen's dimension > 352 pixels. + */ #define RT595_BLIT_WRKRND_ENABLED 1 /* Internal compound symbol */ @@ -51,12 +58,13 @@ #define VG_LITE_BLIT_SPLIT_ENABLED 0 #endif -/** - * BLIT split threshold - BLITs with width or height higher than this value will be done - * in multiple steps. Value must be 16-aligned. Don't change. - */ -#define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 - +#if VG_LITE_BLIT_SPLIT_ENABLED + /** + * BLIT split threshold - BLITs with width or height higher than this value will be done + * in multiple steps. Value must be 16-aligned. Don't change. + */ + #define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 +#endif /********************** * TYPEDEFS @@ -67,63 +75,87 @@ **********************/ /** - * BLock Image Transfer - single direct BLIT. + * Blit single image, with optional opacity. + * + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] opa Opacity * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit); +static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa); + +/** + * Check source memory and stride alignment. + * + * @param[in] src_buf Source buffer + * @param[in] src_stride Stride of source buffer in pixels + * + * @retval LV_RES_OK Alignment OK + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride); + +/** + * Creates matrix that translates to origin of given destination area. + * + * @param[in] dest_area Area with relative coordinates of destination buffer + */ +static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area); + +/** + * Creates matrix that translates to origin of given destination area with transformation (scale or rotate). + * + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dsc Image descriptor + */ +static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc); #if VG_LITE_BLIT_SPLIT_ENABLED - /** - * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. - * - * @param[in,out] area Area to be updated - * @param[in,out] buf Pointer to be updated - */ - static void _align_x(lv_area_t * area, lv_color_t ** buf); +/** + * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. + * + * @param[in/out] area Area to be updated + * @param[in/out] buf Pointer to be updated + */ +static void align_x(lv_area_t * area, lv_color_t ** buf); - /** - * Move buffer pointer to the area start and update variables, Y-axis only. - * - * @param[in,out] area Area to be updated - * @param[in,out] buf Pointer to be updated - * @param[in] stridePx Buffer stride in pixels - */ - static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx); +/** + * Move buffer pointer to the area start and update variables, Y-axis only. + * + * @param[in/out] area Area to be updated + * @param[in/out] buf Pointer to be updated + * @param[in] stride Buffer stride in pixels + */ +static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride); - /** - * Software BLIT as a fall-back scenario. - * - * @param[in] blit BLIT configuration - */ - static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit); - - /** - * Verify BLIT structure - widths, stride, pointer alignment - * - * @param[in] blit BLIT configuration - * @retval LV_RES_OK - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) - */ - static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit); - - /** - * BLock Image Transfer - split BLIT. - * - * @param[in] blit BLIT configuration - * @retval LV_RES_OK Transfer complete - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) - */ - static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit); +/** + * Blit image split in tiles, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity + * + * @retval LV_RES_OK Transfer complete + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa); #endif /********************** * STATIC VARIABLES **********************/ +static vg_lite_matrix_t vgmatrix; + /********************** * MACROS **********************/ @@ -132,98 +164,57 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa) +lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa) { - uint32_t area_size = lv_area_get_size(fill_area); - lv_coord_t area_w = lv_area_get_width(fill_area); - lv_coord_t area_h = lv_area_get_height(fill_area); - - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(area_size < LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT); - } - else { - if(area_size < LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT); - } - - vg_lite_buffer_t vgbuf; - vg_lite_rectangle_t rect; vg_lite_error_t err = VG_LITE_SUCCESS; lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/ vg_lite_color_t vgcol; /* vglite takes ABGR */ + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)dest_buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); if(opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/ - rect.x = fill_area->x1; - rect.y = fill_area->y1; - rect.width = area_w; - rect.height = area_h; + vg_lite_rectangle_t rect = { + .x = dest_area->x1, + .y = dest_area->y1, + .width = lv_area_get_width(dest_area), + .height = lv_area_get_height(dest_area) + }; - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - err = vg_lite_clear(&vgbuf, &rect, vgcol); + err = vg_lite_clear(vgbuf, &rect, vgcol); VG_LITE_ERR_RETURN_INV(err, "Clear failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); } else { /*fill with transparency*/ vg_lite_path_t path; int32_t path_data[] = { /*VG rectangular path*/ - VLC_OP_MOVE, fill_area->x1, fill_area->y1, - VLC_OP_LINE, fill_area->x2 + 1, fill_area->y1, - VLC_OP_LINE, fill_area->x2 + 1, fill_area->y2 + 1, - VLC_OP_LINE, fill_area->x1, fill_area->y2 + 1, - VLC_OP_LINE, fill_area->x1, fill_area->y1, + VLC_OP_MOVE, dest_area->x1, dest_area->y1, + VLC_OP_LINE, dest_area->x2 + 1, dest_area->y1, + VLC_OP_LINE, dest_area->x2 + 1, dest_area->y2 + 1, + VLC_OP_LINE, dest_area->x1, dest_area->y2 + 1, + VLC_OP_LINE, dest_area->x1, dest_area->y1, VLC_OP_END }; err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(path_data), path_data, - (vg_lite_float_t) fill_area->x1, (vg_lite_float_t) fill_area->y1, - ((vg_lite_float_t) fill_area->x2) + 1.0f, ((vg_lite_float_t) fill_area->y2) + 1.0f); + (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_ERR_RETURN_INV(err, "Init path failed."); - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); - col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8); - col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8); - } - col32.ch.alpha = opa; - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - 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); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); VG_LITE_ERR_RETURN_INV(err, "Draw rectangle failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -232,41 +223,64 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv return LV_RES_OK; } -lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa) { - uint32_t dest_size = lv_area_get_size(&blit->dst_area); + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(dest_area); - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT); - } - else { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT); - } + /* Set src_vgbuf structure. */ + lv_vglite_set_src_buf(src_buf, src_area, src_stride); #if VG_LITE_BLIT_SPLIT_ENABLED - return _lv_gpu_nxp_vglite_blit_split(blit); -#endif /* non RT595 */ + lv_color_t * orig_dest_buf = dest_buf; - /* Just pass down */ - return _lv_gpu_nxp_vglite_blit_single(blit); + lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, opa); + + /* Restore the original dest_vgbuf memory address. */ + lv_vglite_set_dest_buf_ptr(orig_dest_buf); + + return rv; +#else + LV_UNUSED(dest_buf); + LV_UNUSED(dest_stride); + + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + return lv_vglite_blit_single(dest_area, src_area, opa); +#endif } -lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit) +lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc) { - uint32_t dest_size = lv_area_get_size(&blit->dst_area); + /* Set vgmatrix. */ + lv_vglite_set_transformation_matrix(dest_area, dsc); - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT); - } - else { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT); - } + /* Set src_vgbuf structure. */ + lv_vglite_set_src_buf(src_buf, src_area, src_stride); - return _lv_gpu_nxp_vglite_blit_single(blit); +#if VG_LITE_BLIT_SPLIT_ENABLED + lv_color_t * orig_dest_buf = dest_buf; + + lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc->opa); + + /* Restore the original dest_vgbuf memory address. */ + lv_vglite_set_dest_buf_ptr(orig_dest_buf); + + return rv; +#else + LV_UNUSED(dest_buf); + LV_UNUSED(dest_stride); + + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + return lv_vglite_blit_single(dest_area, src_area, dsc->opa); +#endif } /********************** @@ -274,223 +288,196 @@ lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit) **********************/ #if VG_LITE_BLIT_SPLIT_ENABLED -static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit) +static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa) { lv_res_t rv = LV_RES_INV; - if(_lv_gpu_nxp_vglite_check_blit(blit) != LV_RES_OK) { - PRINT_BLT("Blit check failed\n"); - return LV_RES_INV; - } + VG_LITE_LOG_TRACE("Blit " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x)", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf); - PRINT_BLT("BLIT from: " - "Area: %03d,%03d - %03d,%03d " - "Addr: %d\n\n", - blit->src_area.x1, blit->src_area.y1, - blit->src_area.x2, blit->src_area.y2, - (uintptr_t) blit->src); - - PRINT_BLT("BLIT to: " - "Area: %03d,%03d - %03d,%03d " - "Addr: %d\n\n", - blit->dst_area.x1, blit->dst_area.y1, - blit->dst_area.x2, blit->dst_area.y2, - (uintptr_t) blit->src); - - /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */ - _align_x(&blit->src_area, (lv_color_t **)&blit->src); - _align_y(&blit->src_area, (lv_color_t **)&blit->src, blit->src_stride / sizeof(lv_color_t)); - _align_x(&blit->dst_area, (lv_color_t **)&blit->dst); - _align_y(&blit->dst_area, (lv_color_t **)&blit->dst, blit->dst_stride / sizeof(lv_color_t)); + /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */ + align_x(src_area, (lv_color_t **)&src_buf); + align_y(src_area, (lv_color_t **)&src_buf, src_stride); + align_x(dest_area, (lv_color_t **)&dest_buf); + align_y(dest_area, (lv_color_t **)&dest_buf, dest_stride); /* Stage 2: If we're in limit, do a single BLIT */ - if((blit->src_area.x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && - (blit->src_area.y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { - PRINT_BLT("Simple blit!\n"); - return _lv_gpu_nxp_vglite_blit_single(blit); + if((src_area->x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && + (src_area->y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + /* Set new dest_vgbuf and src_vgbuf memory addresses. */ + lv_vglite_set_dest_buf_ptr(dest_buf); + lv_vglite_set_src_buf_ptr(src_buf); + + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(dest_area); + + rv = lv_vglite_blit_single(dest_area, src_area, opa); + + VG_LITE_LOG_TRACE("Single " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x) %s", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf, + rv == LV_RES_OK ? "OK!" : "FAILED!"); + + return rv; }; /* Stage 3: Split the BLIT into multiple tiles */ - PRINT_BLT("Split blit!\n"); - - PRINT_BLT("Blit " - "([%03d,%03d], [%03d,%03d]) -> " - "([%03d,%03d], [%03d,%03d]) | " - "([%03dx%03d] -> [%03dx%03d]) | " - "A:(%d -> %d)\n", - blit->src_area.x1, blit->src_area.y1, blit->src_area.x2, blit->src_area.y2, - blit->dst_area.x1, blit->dst_area.y1, blit->dst_area.x2, blit->dst_area.y2, - lv_area_get_width(&blit->src_area), lv_area_get_height(&blit->src_area), - lv_area_get_width(&blit->dst_area), lv_area_get_height(&blit->dst_area), - (uintptr_t) blit->src, (uintptr_t) blit->dst); + VG_LITE_LOG_TRACE("Split " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x)", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf); - lv_coord_t totalWidth = lv_area_get_width(&blit->src_area); - lv_coord_t totalHeight = lv_area_get_height(&blit->src_area); - - lv_gpu_nxp_vglite_blit_info_t tileBlit; + lv_coord_t width = lv_area_get_width(src_area); + lv_coord_t height = lv_area_get_height(src_area); /* Number of tiles needed */ - int totalTilesX = (blit->src_area.x1 + totalWidth + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / - LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; - int totalTilesY = (blit->src_area.y1 + totalHeight + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / - LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + int total_tiles_x = (src_area->x1 + width + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + int total_tiles_y = (src_area->y1 + height + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be * different */ - int shiftSrcX = (blit->src_area.x1 > blit->dst_area.x1) ? (blit->src_area.x1 - blit->dst_area.x1) : 0; - int shiftDstX = (blit->src_area.x1 < blit->dst_area.x1) ? (blit->dst_area.x1 - blit->src_area.x1) : 0; + int shift_src_x = (src_area->x1 > dest_area->x1) ? (src_area->x1 - dest_area->x1) : 0; + int shift_dest_x = (src_area->x1 < dest_area->x1) ? (dest_area->x1 - src_area->x1) : 0; - PRINT_BLT("\n"); - PRINT_BLT("Align shift: src: %d, dst: %d\n", shiftSrcX, shiftDstX); + VG_LITE_LOG_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x); - tileBlit = *blit; + lv_color_t * tile_dest_buf; + lv_area_t tile_dest_area; + const lv_color_t * tile_src_buf; + lv_area_t tile_src_area; - for(int tileY = 0; tileY < totalTilesY; tileY++) { + for(int y = 0; y < total_tiles_y; y++) { - tileBlit.src_area.y1 = 0; /* no vertical alignment, always start from 0 */ - tileBlit.src_area.y2 = totalHeight - tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ + tile_src_area.y1 = 0; /* no vertical alignment, always start from 0 */ + tile_src_area.y2 = height - y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ } - tileBlit.src = blit->src + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->src_stride / sizeof( - lv_color_t); /* stride in px! */ + tile_src_buf = src_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * src_stride; - tileBlit.dst_area.y1 = tileBlit.src_area.y1; /* y has no alignment, always in sync with src */ - tileBlit.dst_area.y2 = tileBlit.src_area.y2; + tile_dest_area.y1 = tile_src_area.y1; /* y has no alignment, always in sync with src */ + tile_dest_area.y2 = tile_src_area.y2; - tileBlit.dst = blit->dst + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->dst_stride / sizeof( - lv_color_t); /* stride in px! */ + tile_dest_buf = dest_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * dest_stride; - for(int tileX = 0; tileX < totalTilesX; tileX++) { + for(int x = 0; x < total_tiles_x; x++) { - if(tileX == 0) { + if(x == 0) { /* 1st tile is special - there may be a gap between buffer start pointer * and area.x1 value, as the pointer has to be aligned. - * tileBlit.src pointer - keep init value from Y-loop. + * tile_src_buf pointer - keep init value from Y-loop. * Also, 1st tile start is not shifted! shift is applied from 2nd tile */ - tileBlit.src_area.x1 = blit->src_area.x1; - tileBlit.dst_area.x1 = blit->dst_area.x1; + tile_src_area.x1 = src_area->x1; + tile_dest_area.x1 = dest_area->x1; } else { /* subsequent tiles always starts from 0, but shifted*/ - tileBlit.src_area.x1 = 0 + shiftSrcX; - tileBlit.dst_area.x1 = 0 + shiftDstX; + tile_src_area.x1 = 0 + shift_src_x; + tile_dest_area.x1 = 0 + shift_dest_x; /* and advance start pointer + 1 tile size */ - tileBlit.src += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; - tileBlit.dst += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + tile_src_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + tile_dest_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; } /* Clip tile end coordinates */ - tileBlit.src_area.x2 = totalWidth + blit->src_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + tile_src_area.x2 = width + src_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; } - tileBlit.dst_area.x2 = totalWidth + blit->dst_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.dst_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.dst_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + tile_dest_area.x2 = width + dest_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_dest_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_dest_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; } - if(tileX < (totalTilesX - 1)) { - /* And adjust end coords if shifted, but not for last tile! */ - tileBlit.src_area.x2 += shiftSrcX; - tileBlit.dst_area.x2 += shiftDstX; + if(x < (total_tiles_x - 1)) { + /* And adjust end coords if shifted, but not for last tile! */ + tile_src_area.x2 += shift_src_x; + tile_dest_area.x2 += shift_dest_x; } - rv = _lv_gpu_nxp_vglite_blit_single(&tileBlit); + if(check_src_alignment(tile_src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); -#if BLIT_DBG_AREAS - lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.dst, tileBlit.dst_width, tileBlit.dst_height, &tileBlit.dst_area, - LV_COLOR_RED); - lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.src, tileBlit.src_width, tileBlit.src_height, &tileBlit.src_area, - LV_COLOR_GREEN); -#endif + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(&tile_dest_area); - PRINT_BLT("Tile [%d, %d]: " - "([%d,%d], [%d,%d]) -> " - "([%d,%d], [%d,%d]) | " - "([%dx%d] -> [%dx%d]) | " - "A:(0x%8X -> 0x%8X) %s\n", - tileX, tileY, - tileBlit.src_area.x1, tileBlit.src_area.y1, tileBlit.src_area.x2, tileBlit.src_area.y2, - tileBlit.dst_area.x1, tileBlit.dst_area.y1, tileBlit.dst_area.x2, tileBlit.dst_area.y2, - lv_area_get_width(&tileBlit.src_area), lv_area_get_height(&tileBlit.src_area), - lv_area_get_width(&tileBlit.dst_area), lv_area_get_height(&tileBlit.dst_area), - (uintptr_t) tileBlit.src, (uintptr_t) tileBlit.dst, - rv == LV_RES_OK ? "OK!" : "!!! FAILED !!!"); + /* Set new dest_vgbuf and src_vgbuf memory addresses. */ + lv_vglite_set_dest_buf_ptr(tile_dest_buf); + lv_vglite_set_src_buf_ptr(tile_src_buf); - if(rv != LV_RES_OK) { /* if anything goes wrong... */ -#if LV_GPU_NXP_VG_LITE_LOG_ERRORS - LV_LOG_ERROR("Split blit failed. Trying SW blit instead."); -#endif - _sw_blit(&tileBlit); - rv = LV_RES_OK; /* Don't report error, as SW BLIT was performed */ + rv = lv_vglite_blit_single(&tile_dest_area, &tile_src_area, opa); + + VG_LITE_LOG_TRACE("Tile [%d, %d] " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x) %s", + x, y, + tile_src_area.x1, tile_src_area.y1, tile_src_area.x2, tile_src_area.y2, + tile_dest_area.x1, tile_dest_area.y1, tile_dest_area.x2, tile_dest_area.y2, + lv_area_get_width(&tile_src_area), lv_area_get_height(&tile_src_area), + lv_area_get_width(&tile_dest_area), lv_area_get_height(&tile_dest_area), + (uintptr_t)tile_src_buf, (uintptr_t)tile_dest_buf, + rv == LV_RES_OK ? "OK!" : "FAILED!"); + + if(rv != LV_RES_OK) { + return rv; } - } - PRINT_BLT(" \n"); } - return rv; /* should never fail */ + return rv; } #endif /* VG_LITE_BLIT_SPLIT_ENABLED */ -static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit) +static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa) { - vg_lite_buffer_t src_vgbuf, dst_vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; - uint32_t rect[4]; - vg_lite_float_t scale = 1.0; + vg_lite_buffer_t * dst_vgbuf = lv_vglite_get_dest_buf(); + vg_lite_buffer_t * src_vgbuf = lv_vglite_get_src_buf(); - if(blit == NULL) { - /*Wrong parameter*/ - return LV_RES_INV; - } - - if(blit->opa < (lv_opa_t) LV_OPA_MIN) { - return LV_RES_OK; /*Nothing to BLIT*/ - } - - /*Wrap src/dst buffer into VG-Lite buffer*/ - if(lv_vglite_init_buf(&src_vgbuf, (uint32_t)blit->src_width, (uint32_t)blit->src_height, (uint32_t)blit->src_stride, - blit->src, true) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - - if(lv_vglite_init_buf(&dst_vgbuf, (uint32_t)blit->dst_width, (uint32_t)blit->dst_height, (uint32_t)blit->dst_stride, - blit->dst, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - - rect[0] = (uint32_t)blit->src_area.x1; /* start x */ - rect[1] = (uint32_t)blit->src_area.y1; /* start y */ - rect[2] = (uint32_t)blit->src_area.x2 - (uint32_t)blit->src_area.x1 + 1U; /* width */ - rect[3] = (uint32_t)blit->src_area.y2 - (uint32_t)blit->src_area.y1 + 1U; /* height */ - - vg_lite_matrix_t matrix; - vg_lite_identity(&matrix); - vg_lite_translate((vg_lite_float_t)blit->dst_area.x1, (vg_lite_float_t)blit->dst_area.y1, &matrix); - - if((blit->angle != 0) || (blit->zoom != LV_IMG_ZOOM_NONE)) { - vg_lite_translate(blit->pivot.x, blit->pivot.y, &matrix); - vg_lite_rotate(blit->angle / 10.0f, &matrix); /* angle is 1/10 degree */ - scale = 1.0f * blit->zoom / LV_IMG_ZOOM_NONE; - vg_lite_scale(scale, scale, &matrix); - vg_lite_translate(0.0f - blit->pivot.x, 0.0f - blit->pivot.y, &matrix); - } - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); + 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 */ + }; uint32_t color; vg_lite_blend_t blend; - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { + 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->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; } else { - uint32_t opa = (uint32_t)blit->opa; if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { color = (opa << 24) | 0x00FFFFFFU; } @@ -498,94 +485,83 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b 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; + src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; + src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; } - err = vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT); - VG_LITE_ERR_RETURN_INV(err, "Blit rectangle failed."); + bool scissoring = lv_area_get_width(dest_area) < lv_area_get_width(src_area) || + lv_area_get_height(dest_area) < lv_area_get_height(src_area); + if(scissoring) { + vg_lite_enable_scissor(); + vg_lite_set_scissor((int32_t)dest_area->x1, (int32_t)dest_area->y1, + (int32_t)lv_area_get_width(dest_area), + (int32_t)lv_area_get_height(dest_area)); + } - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, &vgmatrix, blend, color, VG_LITE_FILTER_POINT); + if(err != VG_LITE_SUCCESS) { + if(scissoring) + vg_lite_disable_scissor(); + VG_LITE_RETURN_INV("Blit rectangle failed."); + } + + if(lv_vglite_run() != LV_RES_OK) { + if(scissoring) + vg_lite_disable_scissor(); + VG_LITE_RETURN_INV("Run failed."); + } + + if(scissoring) + vg_lite_disable_scissor(); return LV_RES_OK; } +static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride) +{ + /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */ + + /* Test for pointer alignment */ + if((((uintptr_t)src_buf) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U) + VG_LITE_RETURN_INV("Src buffer ptr (0x%x) not aligned to 0x%x bytes.", + (size_t)src_buf, LV_ATTRIBUTE_MEM_ALIGN_SIZE); + + /* Test for stride alignment */ + if((src_stride % (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0x0U) + VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.", + src_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); + return LV_RES_OK; +} + +static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area) +{ + vg_lite_identity(&vgmatrix); + vg_lite_translate((vg_lite_float_t)dest_area->x1, (vg_lite_float_t)dest_area->y1, &vgmatrix); +} + +static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc) +{ + lv_vglite_set_translation_matrix(dest_area); + + bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE); + bool has_rotation = (dsc->angle != 0); + + if(has_scale || has_rotation) { + vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &vgmatrix); + if(has_rotation) + vg_lite_rotate(dsc->angle / 10.0f, &vgmatrix); /* angle is 1/10 degree */ + if(has_scale) { + vg_lite_float_t scale = 1.0f * dsc->zoom / LV_IMG_ZOOM_NONE; + vg_lite_scale(scale, scale, &vgmatrix); + } + vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &vgmatrix); + } +} + #if VG_LITE_BLIT_SPLIT_ENABLED - -static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +static void align_x(lv_area_t * area, lv_color_t ** buf) { - int x, y; - - lv_coord_t w = lv_area_get_width(&blit->src_area); - lv_coord_t h = lv_area_get_height(&blit->src_area); - - int32_t srcStridePx = blit->src_stride / (int32_t)sizeof(lv_color_t); - int32_t dstStridePx = blit->dst_stride / (int32_t)sizeof(lv_color_t); - - lv_color_t * src = (lv_color_t *)blit->src + blit->src_area.y1 * srcStridePx + blit->src_area.x1; - lv_color_t * dst = (lv_color_t *)blit->dst + blit->dst_area.y1 * dstStridePx + blit->dst_area.x1; - - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - /* simple copy */ - for(y = 0; y < h; y++) { - lv_memcpy(dst, src, (uint32_t)w * sizeof(lv_color_t)); - src += srcStridePx; - dst += dstStridePx; - } - } - else if(blit->opa >= LV_OPA_MIN) { - /* alpha blending */ - for(y = 0; y < h; y++) { - for(x = 0; x < w; x++) { - dst[x] = lv_color_mix(src[x], dst[x], blit->opa); - } - src += srcStridePx; - dst += dstStridePx; - } - } -} - -static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit) -{ - - /* Test for minimal width */ - if(lv_area_get_width(&blit->src_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) - VG_LITE_RETURN_INV("Src area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->src_area), - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for minimal width */ - if(lv_area_get_width(&blit->dst_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) - VG_LITE_RETURN_INV("Dest area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->dst_area), - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for pointer alignment */ - if((((uintptr_t) blit->src) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0) - VG_LITE_RETURN_INV("Src buffer ptr (0x%X) not aligned to %d.", (size_t) blit->src, LV_ATTRIBUTE_MEM_ALIGN_SIZE); - - /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */ - - /* Test for stride alignment */ - if((blit->src_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) - VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.", blit->src_stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for stride alignment */ - if((blit->dst_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) - VG_LITE_RETURN_INV("Dest buffer stride (%d px) not aligned to %d px.", blit->dst_stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - if((lv_area_get_width(&blit->src_area) != lv_area_get_width(&blit->dst_area)) || - (lv_area_get_height(&blit->src_area) != lv_area_get_height(&blit->dst_area))) - VG_LITE_RETURN_INV("Src and dest buffer areas are not equal."); - - return LV_RES_OK; -} - -static void _align_x(lv_area_t * area, lv_color_t ** buf) -{ - - int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE * 8 / LV_COLOR_DEPTH)); + int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE / sizeof(lv_color_t))); VG_LITE_COND_STOP(alignedAreaStartPx < 0, "Negative X alignment."); area->x1 -= alignedAreaStartPx; @@ -593,17 +569,17 @@ static void _align_x(lv_area_t * area, lv_color_t ** buf) *buf += alignedAreaStartPx; } -static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) +static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride) { int LineToAlignMem; int alignedAreaStartPy; /* find how many lines of pixels will respect memory alignment requirement */ - if(stridePx % (uint32_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE == 0U) { + if((stride % (lv_coord_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) == 0x0U) { alignedAreaStartPy = area->y1; } else { - LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX), + LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)); + VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)), "Complex case: need gcd function."); alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem); VG_LITE_COND_STOP(alignedAreaStartPy < 0, "Negative Y alignment."); @@ -611,7 +587,7 @@ static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) area->y1 -= alignedAreaStartPy; area->y2 -= alignedAreaStartPy; - *buf += (uint32_t)alignedAreaStartPy * stridePx; + *buf += (uint32_t)(alignedAreaStartPy * stride); } #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h index bc448c65a..025d2b5cc 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,64 +41,16 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" /********************* * DEFINES *********************/ -#ifndef LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by VG-Lite with 100% opacity*/ -#define LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by VG-Lite with transparency*/ -#define LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with 100% opacity to be handled by VG-Lite*/ -#define LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT -/** Minimum invalidated area (in pixels) to be synchronized by VG-Lite during buffer sync */ -#define LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with transparency to be handled by VG-Lite*/ -#define LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT 5000 -#endif - /********************** * TYPEDEFS **********************/ -/** - * BLock Image Transfer descriptor structure - */ -typedef struct { - - const lv_color_t * src; /**< Source buffer pointer (must be aligned on 32 bytes)*/ - lv_area_t src_area; /**< Area to be copied from source*/ - lv_coord_t src_width; /**< Source buffer width*/ - lv_coord_t src_height; /**< Source buffer height*/ - int32_t src_stride; /**< Source buffer stride in bytes (must be aligned on 16 px)*/ - - const lv_color_t * dst; /**< Destination buffer pointer (must be aligned on 32 bytes)*/ - lv_area_t dst_area; /**< Target area in destination buffer (must be the same as src_area)*/ - lv_coord_t dst_width; /**< Destination buffer width*/ - lv_coord_t dst_height; /**< Destination buffer height*/ - int32_t dst_stride; /**< Destination buffer stride in bytes (must be aligned on 16 px)*/ - - lv_opa_t opa; /**< Opacity - alpha mix (0 = source not copied, 255 = 100% opaque)*/ - uint32_t angle; /**< Rotation angle (1/10 of degree)*/ - uint32_t zoom; /**< 256 = no zoom (1:1 scale ratio)*/ - lv_point_t pivot; /**< The coordinates of rotation pivot in source image buffer*/ -} lv_gpu_nxp_vglite_blit_info_t; - /********************** * GLOBAL PROTOTYPES **********************/ @@ -106,35 +58,52 @@ typedef struct { /** * Fill area, with optional opacity. * - * @param[in/out] dest_buf Destination buffer pointer (must be aligned on 32 bytes) - * @param[in] dest_width Destination buffer width in pixels (must be aligned on 16 px) - * @param[in] dest_height Destination buffer height in pixels - * @param[in] fill_area Area to be filled - * @param[in] color Fill color + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] color Color * @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill) + * * @retval LV_RES_OK Fill completed * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa); +lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa); /** - * BLock Image Transfer. + * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. + * By default, image is copied directly, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit); +lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa); /** - * BLock Image Transfer with transformation. + * 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/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit); +lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c new file mode 100644 index 000000000..f6e1c4352 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c @@ -0,0 +1,138 @@ +/** + * @file lv_draw_vglite_line.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_vglite_line.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_res_t lv_gpu_nxp_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_color_t vgcol; /* vglite takes ABGR */ + vg_lite_buffer_t * vgbuf = lv_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; + vg_lite_join_style_t join_style = (dsc->round_start || dsc->round_end) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER; + + bool is_dashed = (dsc->dash_width && dsc->dash_gap); + + vg_lite_float_t stroke_dash_pattern[2] = {0, 0}; + uint32_t stroke_dash_count = 0; + vg_lite_float_t stroke_dash_phase = 0; + if(is_dashed) { + stroke_dash_pattern[0] = (vg_lite_float_t)dsc->dash_width; + stroke_dash_pattern[1] = (vg_lite_float_t)dsc->dash_gap; + stroke_dash_count = sizeof(stroke_dash_pattern) / sizeof(vg_lite_float_t); + 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 = lv_vglite_get_blend_mode(dsc->blend_mode); + + /*** Init path ***/ + lv_coord_t width = dsc->width; + + int32_t line_path[] = { /*VG line path*/ + VLC_OP_MOVE, point1->x, point1->y, + VLC_OP_LINE, point2->x, point2->y, + 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); + VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; + vg_lite_identity(&matrix); + + lv_color32_t col32 = { .full = lv_color_to32(dsc->color) }; /*Convert color to RGBA8888*/ + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + /*** Draw line ***/ + err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); + VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed."); + + err = vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count, + stroke_dash_phase, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Set stroke failed."); + + err = vg_lite_update_stroke(&path); + VG_LITE_ERR_RETURN_INV(err, "Update stroke failed."); + + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Draw line failed."); + + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); + + err = vg_lite_clear_path(&path); + VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); + + return LV_RES_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h new file mode 100644 index 000000000..cbd4b95ec --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h @@ -0,0 +1,83 @@ +/** + * @file lv_draw_vglite_line.h + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_VGLITE_LINE_H +#define LV_DRAW_VGLITE_LINE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_utils.h" +#include "../../lv_draw_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw line shape with effects + * + * @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] dsc Line description structure (width, rounded ending, opacity, ...) + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_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); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_RECT_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c index bc1d55c85..39ccaa481 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,10 +34,28 @@ #include "lv_draw_vglite_rect.h" #if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" +#include /********************* * DEFINES *********************/ +/********************* + * DEFINES + *********************/ + +/* Path data sizes for different elements */ +#define CUBIC_PATH_DATA_SIZE 7 /* 1 opcode, 6 arguments */ +#define LINE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */ +#define MOVE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */ +#define END_PATH_DATA_SIZE 1 /* 1 opcode, 0 arguments */ +/* Maximum possible rectangle path size + * is in the rounded rectangle case: + * - 1 move for the path start + * - 4 cubics for the corners + * - 4 lines for the sides + * - 1 end for the path end */ +#define RECT_PATH_DATA_MAX_SIZE 1 * MOVE_PATH_DATA_SIZE + 4 * CUBIC_PATH_DATA_SIZE + 4 * LINE_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE /********************** * TYPEDEFS @@ -47,6 +65,18 @@ * STATIC PROTOTYPES **********************/ +/** + * Generates path data for rectangle drawing. + * + * @param[in/out] path The path data to initialize + * @param[in/out] path_size The resulting size of the created path data + * @param[in] dsc The style descriptor for the rectangle to be drawn + * @param[in] coords The coordinates of the rectangle to be drawn + */ +static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size, + lv_coord_t radius, + const lv_area_t * coords); + /********************** * STATIC VARIABLES **********************/ @@ -59,94 +89,37 @@ * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc) { - vg_lite_buffer_t vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); - vg_lite_path_t path; - vg_lite_color_t vgcol; /* vglite takes ABGR */ - vg_lite_matrix_t matrix; lv_coord_t width = lv_area_get_width(coords); lv_coord_t height = lv_area_get_height(coords); - vg_lite_linear_gradient_t gradient; - vg_lite_matrix_t * grad_matrix; + vg_lite_color_t vgcol; + lv_coord_t radius = dsc->radius; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); if(dsc->radius < 0) return LV_RES_INV; - /* Make areas relative to draw buffer */ - lv_area_t rel_coords; - lv_area_copy(&rel_coords, coords); - lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - lv_area_t rel_clip; - lv_area_copy(&rel_clip, draw_ctx->clip_area); - lv_area_move(&rel_clip, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - /*** Init destination buffer ***/ - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - /*** Init path ***/ - int32_t rad = dsc->radius; - if(dsc->radius == LV_RADIUS_CIRCLE) { - rad = (width > height) ? height / 2 : width / 2; - } - - if((dsc->radius == LV_RADIUS_CIRCLE) && (width == height)) { - float tang = ((float)rad * BEZIER_OPTIM_CIRCLE); - int32_t cpoff = (int32_t)tang; - int32_t circle_path[] = { /*VG circle path*/ - VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1, - VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */ - VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */ - VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */ - VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */ - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(circle_path), circle_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } - else if(dsc->radius > 0) { - float tang = ((float)rad * BEZIER_OPTIM_CIRCLE); - int32_t cpoff = (int32_t)tang; - int32_t rounded_path[] = { /*VG rounded rectangular path*/ - VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 - rad + 1, rel_coords.y1, /* top */ - VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */ - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 - rad + 1, /* right */ - VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */ - VLC_OP_LINE, rel_coords.x1 + rad, rel_coords.y2 + 1, /* bottom */ - VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */ - VLC_OP_LINE, rel_coords.x1, rel_coords.y1 + rad, /* left */ - VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */ - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(rounded_path), rounded_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } - else { - int32_t rect_path[] = { /*VG rectangular path*/ - VLC_OP_MOVE, rel_coords.x1, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 + 1, - VLC_OP_LINE, rel_coords.x1, rel_coords.y2 + 1, - VLC_OP_LINE, rel_coords.x1, rel_coords.y1, - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(rect_path), rect_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } + int32_t path_data[RECT_PATH_DATA_MAX_SIZE]; + uint32_t path_data_size; + lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords); + vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW; + 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); VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; vg_lite_identity(&matrix); + vg_lite_matrix_t * grad_matrix; + vg_lite_linear_gradient_t gradient; + /*** Init Color/Gradient ***/ if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) { uint32_t colors[2]; @@ -154,18 +127,14 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ lv_color32_t col32[2]; /* Gradient setup */ - uint8_t cnt = MAX(dsc->bg_grad.stops_count, 2); + uint8_t cnt = LV_MAX(dsc->bg_grad.stops_count, 2); for(uint8_t i = 0; i < cnt; i++) { col32[i].full = lv_color_to32(dsc->bg_grad.stops[i].color); /*Convert color to RGBA8888*/ stops[i] = dsc->bg_grad.stops[i].frac; -#if LV_COLOR_DEPTH==16 - colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.blue << 16) | - ((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.red; -#else /*LV_COLOR_DEPTH==32*/ - /* watchout: red and blue color components are inverted versus vg_lite_color_t order */ - colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.red << 16) | - ((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.blue; -#endif + + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_ABGR8888 : VG_LITE_ARGB8888; + if(lv_vglite_premult_and_swizzle(&colors[i], col32[i], dsc->bg_opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); } lv_memset_00(&gradient, sizeof(vg_lite_linear_gradient_t)); @@ -181,7 +150,7 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ grad_matrix = vg_lite_get_grad_matrix(&gradient); vg_lite_identity(grad_matrix); - vg_lite_translate((float)rel_coords.x1, (float)rel_coords.y1, 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); @@ -192,39 +161,22 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ } } - lv_opa_t bg_opa = dsc->bg_opa; lv_color32_t bg_col32 = {.full = lv_color_to32(dsc->bg_color)}; /*Convert color to RGBA8888*/ - if(bg_opa <= (lv_opa_t)LV_OPA_MAX) { - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - bg_col32.ch.red = (uint8_t)(((uint16_t)bg_col32.ch.red * bg_opa) >> 8); - bg_col32.ch.green = (uint8_t)(((uint16_t)bg_col32.ch.green * bg_opa) >> 8); - bg_col32.ch.blue = (uint8_t)(((uint16_t)bg_col32.ch.blue * bg_opa) >> 8); - } - bg_col32.ch.alpha = bg_opa; - } - -#if LV_COLOR_DEPTH==16 - vgcol = bg_col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)bg_col32.ch.alpha << 24) | ((uint32_t)bg_col32.ch.blue << 16) | - ((uint32_t)bg_col32.ch.green << 8) | (uint32_t)bg_col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, bg_col32, dsc->bg_opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); /*** Draw rectangle ***/ if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) { - err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); } else { - err = vg_lite_draw_gradient(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); + err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); } VG_LITE_ERR_RETURN_INV(err, "Draw gradient failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -237,6 +189,261 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ return LV_RES_OK; } +lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc, bool border) +{ + vg_lite_error_t err = VG_LITE_SUCCESS; + vg_lite_color_t vgcol; /* vglite takes ABGR */ + lv_coord_t radius = dsc->radius; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); + + if(radius < 0) + return LV_RES_INV; + + if(border) { + /* Draw border - only has radius if object has radius*/ + lv_coord_t border_half = (lv_coord_t)floor(dsc->border_width / 2.0f); + if(radius > border_half) + radius = radius - border_half; + } + else { + /* Draw outline - always has radius, leave the same radius in the circle case */ + lv_coord_t outline_half = (lv_coord_t)ceil(dsc->outline_width / 2.0f); + if(radius < (lv_coord_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; + + /* Choose vglite blend mode based on given lvgl blend mode */ + vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode); + + /*** Init path ***/ + int32_t path_data[RECT_PATH_DATA_MAX_SIZE]; + uint32_t path_data_size; + lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords); + vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW; + + 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); + VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; + vg_lite_identity(&matrix); + + lv_opa_t opa; + lv_color32_t col32; + lv_coord_t line_width; + + if(border) { + opa = dsc->border_opa; + col32.full = lv_color_to32(dsc->border_color); /*Convert color to RGBA8888*/ + line_width = dsc->border_width; + } + else { + opa = dsc->outline_opa; + col32.full = lv_color_to32(dsc->outline_color); /*Convert color to RGBA8888*/ + line_width = dsc->outline_width; + } + + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + /*** Draw border ***/ + err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); + VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed."); + + err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Set stroke failed."); + + err = vg_lite_update_stroke(&path); + VG_LITE_ERR_RETURN_INV(err, "Update stroke failed."); + + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Draw border failed."); + + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); + + err = vg_lite_clear_path(&path); + VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); + + return LV_RES_OK; + +} + +static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size, + lv_coord_t radius, + const lv_area_t * coords) +{ + lv_coord_t rect_width = lv_area_get_width(coords); + lv_coord_t rect_height = lv_area_get_height(coords); + + /* Get the final radius. Can't be larger than the half of the shortest side */ + int32_t shortest_side = LV_MIN(rect_width, rect_height); + int32_t final_radius = LV_MIN(radius, shortest_side / 2); + + /* Path data element index */ + uint8_t pidx = 0; + + if((radius == (lv_coord_t)LV_RADIUS_CIRCLE) && (rect_width == rect_height)) { + + /* Get the control point offset for rounded cases */ + int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE); + + /* Circle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y1; + + /* Top-right arc */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius; + + /* Bottom-right arc*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = cpoff; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + + /* Bottom-left arc */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Top-left arc*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + else if(radius > 0) { + /* Get the control point offset for rounded cases */ + int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE); + + /* Rounded rectangle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y1; + + /* Top side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 - final_radius + 1; // Extended for VGLite + path_data[pidx++] = coords->y1; + + /* Top-right corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius; + + /* Right side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y2 - final_radius + 1; // Extended for VGLite + + /* Bottom-right corner*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = cpoff; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + + /* Bottom side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Bottom-left corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Left side*/ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1 + final_radius; + + /* Top-left corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + else { + /* Non-rounded rectangle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1; + + /* Top side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y1; + + /* Right side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Bottom side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Left side*/ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + + /* Resulting path size */ + *path_data_size = pidx * sizeof(int32_t); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h index d708e7b42..795822746 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" #include "../../lv_draw_rect.h" /********************* @@ -56,13 +56,33 @@ extern "C" { **********************/ /** - * Draw rectangle shape with effects (rounded corners, gradient) + * 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] dsc Description of the rectangle background + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * - * @param draw_ctx drawing context - * @param dsc description of the rectangle - * @param coords the area where rectangle is clipped */ -lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc); + +/** + * 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] dsc Description of the rectangle border/outline + * @param[in] border True for border, False for outline + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + * + */ +lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc, bool border); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c deleted file mode 100644 index f65ec1d48..000000000 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file lv_gpu_nxp_vglite.c - * - */ - -/** - * MIT License - * - * Copyright 2020-2022 NXP - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next paragraph) - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_gpu_nxp_vglite.h" - -#if LV_USE_GPU_NXP_VG_LITE -#include "../../../core/lv_refr.h" -#if BLIT_DBG_AREAS - #include "lv_draw_vglite_blend.h" -#endif - -/********************* - * DEFINES - *********************/ - -#if LV_COLOR_DEPTH==16 - #define VG_LITE_PX_FMT VG_LITE_RGB565 -#elif LV_COLOR_DEPTH==32 - #define VG_LITE_PX_FMT VG_LITE_BGRA8888 -#else - #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. -#endif - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr, bool source) -{ - /*Test for memory alignment*/ - if((((uintptr_t)ptr) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U) - VG_LITE_RETURN_INV("%s buffer (0x%x) not aligned to %d.", source ? "Src" : "Dest", - (size_t) ptr, LV_ATTRIBUTE_MEM_ALIGN_SIZE); - - /*Test for stride alignment*/ - if(source && (stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t))) != 0x0U) - VG_LITE_RETURN_INV("Src buffer stride (%d bytes) not aligned to %d bytes.", stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)); - - vgbuf->format = VG_LITE_PX_FMT; - vgbuf->tiled = VG_LITE_LINEAR; - vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE; - vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE; - - vgbuf->width = (int32_t)width; - vgbuf->height = (int32_t)height; - vgbuf->stride = (int32_t)stride; - - lv_memset_00(&vgbuf->yuv, sizeof(vgbuf->yuv)); - - vgbuf->memory = (void *)ptr; - vgbuf->address = (uint32_t)vgbuf->memory; - vgbuf->handle = NULL; - - return LV_RES_OK; -} - -#if BLIT_DBG_AREAS -void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - lv_area_t * fill_area, lv_color_t color) -{ - lv_area_t a; - - /* top line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x2; - a.y1 = fill_area->y1; - a.y2 = fill_area->y1; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - - /* bottom line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x2; - a.y1 = fill_area->y2; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - /* left line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x1; - a.y1 = fill_area->y1; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - /* right line */ - a.x1 = fill_area->x2; - a.x2 = fill_area->x2; - a.y1 = fill_area->y1; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); -} -#endif /* BLIT_DBG_AREAS */ - -void lv_vglite_invalidate_cache(void) -{ - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->clean_dcache_cb) - disp->driver->clean_dcache_cb(disp->driver); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c new file mode 100644 index 000000000..f6325ab2a --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c @@ -0,0 +1,143 @@ +/** + * @file lv_vglite_buf.c + * + */ + +/** + * MIT License + * + * Copyright 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_vglite_buf.h" + +#if LV_USE_GPU_NXP_VG_LITE + +/********************* + * DEFINES + *********************/ + +#if LV_COLOR_DEPTH == 16 + #define VG_LITE_PX_FMT VG_LITE_RGB565 +#elif LV_COLOR_DEPTH == 32 + #define VG_LITE_PX_FMT VG_LITE_BGRA8888 +#else + #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); +static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf); +static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf, + const lv_area_t * area, lv_coord_t stride); + +/********************** + * STATIC VARIABLES + **********************/ + +static vg_lite_buffer_t dest_vgbuf; +static vg_lite_buffer_t src_vgbuf; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + lv_vglite_set_dest_buf(buf, area, stride); +} + +vg_lite_buffer_t * lv_vglite_get_dest_buf(void) +{ + return &dest_vgbuf; +} + +vg_lite_buffer_t * lv_vglite_get_src_buf(void) +{ + return &src_vgbuf; +} + +void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf) +{ + lv_vglite_set_buf_ptr(&dest_vgbuf, buf); +} + +void lv_vglite_set_src_buf_ptr(const lv_color_t * buf) +{ + lv_vglite_set_buf_ptr(&src_vgbuf, buf); +} + +void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + if(src_vgbuf.memory != (void *)buf) + lv_vglite_set_buf(&src_vgbuf, buf, area, stride); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + lv_vglite_set_buf(&dest_vgbuf, buf, area, stride); +} + +static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf) +{ + vgbuf->memory = (void *)buf; + vgbuf->address = (uint32_t)vgbuf->memory; +} + +static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf, + const lv_area_t * area, lv_coord_t stride) +{ + vgbuf->format = VG_LITE_PX_FMT; + vgbuf->tiled = VG_LITE_LINEAR; + vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE; + vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE; + + vgbuf->width = (int32_t)lv_area_get_width(area); + vgbuf->height = (int32_t)lv_area_get_height(area); + vgbuf->stride = (int32_t)(stride) * sizeof(lv_color_t); + + lv_memset_00(&vgbuf->yuv, sizeof(vgbuf->yuv)); + + vgbuf->memory = (void *)buf; + vgbuf->address = (uint32_t)vgbuf->memory; + vgbuf->handle = NULL; +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h new file mode 100644 index 000000000..9219dca05 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h @@ -0,0 +1,113 @@ +/** + * @file lv_vglite_buf.h + * + */ + +/** + * MIT License + * + * Copyright 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_VGLITE_BUF_H +#define LV_VGLITE_BUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "vg_lite.h" +#include "../../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Init vglite destination buffer. It will be done once per frame. + * + * @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode) + * @param[in] area Destination buffer area (for width and height) + * @param[in] stride Stride of destination buffer + */ +void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); + +/** + * Get vglite destination buffer pointer. + * + * @retval The vglite destination buffer + */ +vg_lite_buffer_t * lv_vglite_get_dest_buf(void); + +/** + * Get vglite source buffer pointer. + * + * @retval The vglite source buffer + */ +vg_lite_buffer_t * lv_vglite_get_src_buf(void); + +/** + * Set vglite destination buffer address only. + * + * @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode) + */ +void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf); + +/** + * Set vglite source buffer address only. + * + * @param[in] buf Source buffer address + */ +void lv_vglite_set_src_buf_ptr(const lv_color_t * buf); + +/** + * Set vglite source buffer. It will be done only if buffer addreess is different. + * + * @param[in] buf Source buffer address + * @param[in] area Source buffer area (for width and height) + * @param[in] stride Stride of source buffer + */ +void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_VGLITE_BUF_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c new file mode 100644 index 000000000..adc9f7712 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c @@ -0,0 +1,149 @@ +/** + * @file lv_vglite_utils.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_vglite_utils.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "../../../core/lv_refr.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/** + * Clean and invalidate cache. + */ +static inline void invalidate_cache(void); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_res_t lv_vglite_run(void) +{ + invalidate_cache(); + + VG_LITE_ERR_RETURN_INV(vg_lite_flush(), "Flush failed."); + + return LV_RES_OK; +} + +lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa, + vg_lite_buffer_format_t vg_col_format) +{ + + lv_color32_t lv_col32_premul = lv_col32; + if(opa <= (lv_opa_t)LV_OPA_MAX) { + /* Only pre-multiply color if hardware pre-multiplication is not present */ + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { + lv_col32_premul.ch.red = (uint8_t)(((uint16_t)lv_col32.ch.red * opa) >> 8); + lv_col32_premul.ch.green = (uint8_t)(((uint16_t)lv_col32.ch.green * opa) >> 8); + lv_col32_premul.ch.blue = (uint8_t)(((uint16_t)lv_col32.ch.blue * opa) >> 8); + } + lv_col32_premul.ch.alpha = opa; + } + + switch(vg_col_format) { + case VG_LITE_BGRA8888: + *vg_col32 = lv_col32_premul.full; + break; + case VG_LITE_RGBA8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.red << 24) | ((uint32_t)lv_col32_premul.ch.green << 16) | + ((uint32_t)lv_col32_premul.ch.blue << 8) | (uint32_t)lv_col32_premul.ch.alpha; + break; + case VG_LITE_ABGR8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.blue << 16) | + ((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.red; + break; + case VG_LITE_ARGB8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.red << 16) | + ((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.blue; + break; + default: + return LV_RES_INV; + } + + return LV_RES_OK; +} + +vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode) +{ + vg_lite_blend_t vg_blend_mode; + 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; + case LV_BLEND_MODE_REPLACE: + vg_blend_mode = VG_LITE_BLEND_NONE; + break; + default: + vg_blend_mode = VG_LITE_BLEND_SRC_OVER; + break; + } + return vg_blend_mode; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static inline void invalidate_cache(void) +{ + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver->clean_dcache_cb) + disp->driver->clean_dcache_cb(disp->driver); +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h similarity index 65% rename from lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h rename to lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h index c22cae185..9ff4de02f 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h @@ -1,12 +1,12 @@ /** - * @file lv_gpu_nxp_vglite.h + * @file lv_vglite_utils.h * */ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,8 +27,8 @@ * */ -#ifndef LV_GPU_NXP_VGLITE_H -#define LV_GPU_NXP_VGLITE_H +#ifndef LV_VGLITE_UTILS_H +#define LV_VGLITE_UTILS_H #ifdef __cplusplus extern "C" { @@ -43,40 +43,21 @@ extern "C" { #include "vg_lite.h" #include "../../sw/lv_draw_sw.h" #include "../../../misc/lv_log.h" -#include "fsl_debug_console.h" /********************* * DEFINES *********************/ -/** Use this symbol as limit to disable feature (value has to be larger than supported resolution) */ -#define LV_GPU_NXP_VG_LITE_FEATURE_DISABLED (1920*1080+1) - -/** Stride in px required by VG-Lite HW. Don't change this. */ -#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U - #ifndef LV_GPU_NXP_VG_LITE_LOG_ERRORS /** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ #define LV_GPU_NXP_VG_LITE_LOG_ERRORS 1 #endif #ifndef LV_GPU_NXP_VG_LITE_LOG_TRACES -/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ +/** Enable logging of VG-Lite traces (\see LV_LOG_ERROR)*/ #define LV_GPU_NXP_VG_LITE_LOG_TRACES 0 #endif -/* Draw rectangles around BLIT tiles */ -#define BLIT_DBG_AREAS 0 - -/* Print detailed info to SDK console (NOT to LVGL log system) */ -#define BLIT_DBG_VERBOSE 0 - -/* Verbose debug print */ -#if BLIT_DBG_VERBOSE -#define PRINT_BLT PRINTF -#else -#define PRINT_BLT(...) -#endif /* The optimal Bezier control point offset for radial unit * see: https://spencermortensen.com/articles/bezier-circle/ @@ -95,36 +76,35 @@ extern "C" { **********************/ /** - * Fills vg_lite_buffer_t structure according given parameters. + * Premultiplies and swizzles given LVGL 32bit color to obtain vglite color. * - * @param[in/out] vgbuf Buffer structure to be filled - * @param[in] width Width of buffer in pixels - * @param[in] height Height of buffer in pixels - * @param[in] stride Stride of the buffer in bytes - * @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements) - * @param[in] source Boolean to check if this is a source buffer - */ -lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr, bool source); - -#if BLIT_DBG_AREAS -/** - * Draw a simple rectangle, 1 px line width. + * @param[in/out] vg_col32 The obtained vglite color + * @param[in] lv_col32 The initial LVGL 32bit color + * @param[in] opa The opacity to premultiply with + * @param[in] vg_col_format The format of the resulting vglite color * - * @param dest_buf Destination buffer - * @param dest_width Destination buffer width (must be aligned on 16px) - * @param dest_height Destination buffer height - * @param fill_area Rectangle coordinates - * @param color Rectangle color + * @retval LV_RES_OK Operation completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - lv_area_t * fill_area, lv_color_t color); -#endif +lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa, + vg_lite_buffer_format_t vg_col_format); /** - * Clean & invalidate cache. + * Get vglite blend mode. + * + * @param[in] lv_blend_mode The LVGL blend mode + * + * @retval The vglite blend mode */ -void lv_vglite_invalidate_cache(void); +vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode); + +/** + * Clear cache and flush command to VG-Lite. + * + * @retval LV_RES_OK Run completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_vglite_run(void); /********************** * MACROS @@ -142,7 +122,8 @@ void lv_vglite_invalidate_cache(void); #define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \ do { \ if(err != VG_LITE_SUCCESS) { \ - LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + LV_LOG_ERROR(fmt" (err = %d)", \ + err, ##__VA_ARGS__); \ return LV_RES_INV; \ } \ } while (0) @@ -158,7 +139,7 @@ void lv_vglite_invalidate_cache(void); #if LV_GPU_NXP_VG_LITE_LOG_TRACES #define VG_LITE_LOG_TRACE(fmt, ...) \ do { \ - LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + LV_LOG(fmt, ##__VA_ARGS__); \ } while (0) #define VG_LITE_RETURN_INV(fmt, ...) \ @@ -182,4 +163,4 @@ void lv_vglite_invalidate_cache(void); } /*extern "C"*/ #endif -#endif /*LV_GPU_NXP_VGLITE_H*/ +#endif /*LV_VGLITE_UTILS_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c index a303ac764..6418a0af6 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c @@ -27,6 +27,8 @@ * DEFINES *********************/ +#define FRAG_SPACING 3 + /********************** * TYPEDEFS **********************/ @@ -37,6 +39,23 @@ typedef struct { lv_coord_t size; } lv_draw_rect_bg_key_t; +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; + uint8_t stops_count; + lv_grad_dir_t dir; +} lv_draw_rect_grad_strip_key_t; + +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; + uint8_t stops_count; + lv_grad_dir_t dir; + lv_coord_t w; + lv_coord_t h; + lv_coord_t radius; +} lv_draw_rect_grad_frag_key_t; + typedef struct { lv_sdl_cache_key_magic_t magic; lv_coord_t radius; @@ -57,6 +76,12 @@ typedef struct { static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); +static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_grad_dsc_t * grad, bool blend_mod); + +static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc); + static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); @@ -81,6 +106,11 @@ static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_c static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size); +static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h, + lv_coord_t radius); + +static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad); + static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur); static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area, @@ -148,16 +178,93 @@ void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius) { lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, radius); - lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1}; - lv_area_t coords_frag = {0, 0, radius - 1, radius - 1}; SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { + lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1}; + lv_area_t coords_frag = {0, 0, radius - 1, radius - 1}; lv_draw_mask_radius_param_t mask_rout_param; lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false); int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1); + SDL_assert(texture != NULL); lv_draw_mask_remove_id(mask_id); - SDL_assert(texture); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); + } + return texture; +} + +SDL_Texture * lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, lv_coord_t w, + lv_coord_t h, lv_coord_t radius) +{ + lv_draw_rect_grad_frag_key_t key = rect_grad_frag_key_create(grad, w, h, radius); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(texture == NULL) { + lv_area_t coords = {0, 0, radius * 2 + FRAG_SPACING - 1, radius * 2 + FRAG_SPACING - 1}; + texture = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, + lv_area_get_width(&coords), lv_area_get_height(&coords)); + SDL_assert(texture != NULL); + + lv_draw_mask_radius_param_t mask_rout_param; + lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false); + int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); + SDL_Texture * mask = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords, &mask_id, 1); + SDL_assert(mask != NULL); + SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE); + lv_draw_mask_remove_id(mask_id); + + SDL_Texture * target_backup = SDL_GetRenderTarget(ctx->renderer); + SDL_SetRenderTarget(ctx->renderer, texture); + SDL_RenderCopy(ctx->renderer, mask, NULL, NULL); + SDL_DestroyTexture(mask); + + lv_area_t blend_coords = {.x1 = 0, .y1 = 0, .x2 = w - 1, .y2 = h - 1}; + lv_area_t draw_area = {.x1 = 0, .y1 = 0, .x2 = radius - 1, .y2 = radius - 1}; + /* Align to top left */ + lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_LEFT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_LEFT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to top right */ + lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_RIGHT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to bottom right */ + lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to bottom left */ + lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_LEFT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_LEFT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + SDL_SetRenderTarget(ctx->renderer, target_backup); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); + } + return texture; +} + +SDL_Texture * lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad) +{ + lv_draw_rect_grad_strip_key_t key = rect_grad_strip_key_create(grad); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(texture == NULL) { + Uint32 amask = 0xFF000000; + Uint32 rmask = 0x00FF0000; + Uint32 gmask = 0x0000FF00; + Uint32 bmask = 0x000000FF; + lv_color_t pixels[256]; + for(int i = 0; i < 256; i++) { + pixels[i] = lv_gradient_calculate(grad, 256, i); + } + int width = grad->dir == LV_GRAD_DIR_VER ? 1 : 256; + int height = grad->dir == LV_GRAD_DIR_VER ? 256 : 1; + SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(pixels, width, height, LV_COLOR_DEPTH, width * LV_COLOR_DEPTH / 8, + rmask, gmask, bmask, amask); + texture = SDL_CreateTextureFromSurface(ctx->renderer, surface); + SDL_assert(texture != NULL); + SDL_FreeSurface(surface); lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); } return texture; @@ -193,7 +300,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, sy, dw, dh}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -212,7 +319,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 3 + sy, dw, dh}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + FRAG_SPACING + sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -220,7 +327,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL); } } - /* Lower left, right edge should not be clip */ + /* Lower left, right edge should not be clipped */ corner_area.x1 = coords->x1; corner_area.x2 = coords->x1 + frag_size - 1; if(_lv_area_intersect(&dst_area, &corner_area, clip)) { @@ -231,7 +338,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {sx, frag_size + 3 + sy, dw, dh}; + SDL_Rect src_rect = {sx, frag_size + FRAG_SPACING + sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -252,9 +359,23 @@ static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, con if(dsc->bg_opa == 0) { return; } - SDL_Color bg_color; - lv_color_to_sdl_color(&dsc->bg_color, &bg_color); lv_coord_t radius = dsc->radius; + SDL_Color bg_color; + if(dsc->bg_grad.dir == LV_GRAD_DIR_NONE) { + lv_color_to_sdl_color(&dsc->bg_color, &bg_color); + } + else if(dsc->bg_grad.stops_count == 1) { + lv_color_to_sdl_color(&dsc->bg_grad.stops[0].color, &bg_color); + } + else { + if(radius <= 0) { + draw_bg_grad_simple(ctx, coords, draw_area, &dsc->bg_grad, false); + } + else { + draw_bg_grad_radius(ctx, coords, draw_area, dsc); + } + return; + } if(radius <= 0) { SDL_Rect rect; lv_area_to_sdl_rect(draw_area, &rect); @@ -277,9 +398,111 @@ static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, con frag_render_center(ctx->renderer, texture, real_radius, coords, draw_area, false); } +static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_grad_dsc_t * grad, bool blend_mod) +{ + SDL_Rect dstrect; + lv_area_to_sdl_rect(draw_area, &dstrect); + SDL_Rect srcrect; + if(grad->dir == LV_GRAD_DIR_VER) { + lv_coord_t coords_h = lv_area_get_height(coords); + srcrect.x = 0; + srcrect.y = (draw_area->y1 - coords->y1) * 255 / coords_h; + srcrect.w = 1; + srcrect.h = dstrect.h * 256 / coords_h; + + if(srcrect.y < 0 || srcrect.y > 255) { + return; + } + } + else { + lv_coord_t coords_w = lv_area_get_width(coords); + srcrect.x = (draw_area->x1 - coords->x1) * 255 / coords_w; + srcrect.y = 0; + srcrect.w = dstrect.w * 256 / coords_w; + srcrect.h = 1; + + if(srcrect.x < 0 || srcrect.x > 255) { + return; + } + } + + SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_strip_obtain(ctx, grad); + if(blend_mod) { + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_MOD); + } + else { + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND); + } + + SDL_RenderCopy(ctx->renderer, grad_texture, &srcrect, &dstrect); +} + +static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc) +{ + lv_coord_t radius = dsc->radius; + /*A small texture with a quarter of the rect is enough*/ + lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords); + lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius); + SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_frag_obtain(ctx, &dsc->bg_grad, bg_w, bg_h, radius); + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND); + + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, grad_texture, real_radius, coords, draw_area, true); + lv_area_t part_coords; + lv_area_t part_area; + if(bg_w > radius * 2) { + /*Draw left, middle, right*/ + part_coords.x1 = 0; + part_coords.x2 = radius - 1; + part_coords.y1 = radius; + part_coords.y2 = bg_h - radius - 1; + + lv_area_align(coords, &part_coords, LV_ALIGN_LEFT_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + lv_area_align(coords, &part_coords, LV_ALIGN_RIGHT_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + part_coords.x1 = radius; + part_coords.x2 = bg_w - radius - 1; + part_coords.y1 = 0; + part_coords.y2 = bg_h - 1; + lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + } + else if(bg_h > radius * 2) { + /*Draw top, middle, bottom*/ + part_coords.x1 = radius; + part_coords.x2 = bg_w - radius - 1; + part_coords.y1 = 0; + part_coords.y2 = radius - 1; + + lv_area_align(coords, &part_coords, LV_ALIGN_TOP_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + lv_area_align(coords, &part_coords, LV_ALIGN_BOTTOM_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + part_coords.x1 = 0; + part_coords.x2 = bg_w - 1; + part_coords.y1 = radius; + part_coords.y2 = bg_h - radius - 1; + lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + } +} + static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc) { + LV_UNUSED(draw_area); if(SKIP_IMAGE(dsc)) return; lv_img_src_t src_type = lv_img_src_get_type(dsc->bg_img_src); @@ -521,8 +744,8 @@ static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer lv_coord_t frag_size = LV_MAX(radius, max_side); SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { - /* Create a mask texture with size of (frag_size * 2 + 3) */ - const lv_area_t frag_area = {0, 0, frag_size * 2 + 2, frag_size * 2 + 2}; + /* Create a mask texture with size of (frag_size * 2 + FRAG_SPACING) */ + const lv_area_t frag_area = {0, 0, frag_size * 2 + FRAG_SPACING - 1, frag_size * 2 + FRAG_SPACING - 1}; /*Create mask for the outer area*/ int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV}; @@ -595,7 +818,7 @@ static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_ lv_coord_t dh = lv_area_get_height(&dst_area); if(full) { lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1); - SDL_Rect src_rect = {frag_size + 1, frag_size + 3 + sy, 1, dh}; + SDL_Rect src_rect = {frag_size + 1, frag_size + FRAG_SPACING + sy, 1, dh}; SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } else { @@ -634,7 +857,7 @@ static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_ lv_coord_t dw = lv_area_get_width(&dst_area); if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1); - SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 1, dw, 1}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + 1, dw, 1}; SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } else { @@ -682,6 +905,38 @@ static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t si return key; } +static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h, + lv_coord_t radius) +{ + lv_draw_rect_grad_frag_key_t key; + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD; + key.stops_count = grad->stops_count; + key.dir = grad->dir; + for(uint8_t i = 0; i < grad->stops_count; i++) { + key.stops[i].frac = grad->stops[i].frac; + key.stops[i].color = grad->stops[i].color; + } + key.w = w; + key.h = h; + key.radius = radius; + return key; +} + +static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad) +{ + lv_draw_rect_grad_strip_key_t key; + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD; + key.stops_count = grad->stops_count; + key.dir = grad->dir; + for(uint8_t i = 0; i < grad->stops_count; i++) { + key.stops[i].frac = grad->stops[i].frac; + key.stops[i].color = grad->stops[i].color; + } + return key; +} + static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur) { lv_draw_rect_shadow_key_t key; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h index 1e9be3445..3472af31b 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h @@ -59,6 +59,11 @@ typedef struct lv_draw_sdl_rect_header_t { SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius); +SDL_Texture * lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, lv_coord_t w, + lv_coord_t h, lv_coord_t radius); + +SDL_Texture * lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad); + void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords, const lv_area_t * clip, bool full); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h index dc8b578e6..1bbf17cd8 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h @@ -50,6 +50,7 @@ typedef enum { LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31, LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32, LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33, + LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD = 0x34, LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH = 0x41, LV_GPU_CACHE_KEY_MAGIC_MASK = 0x51, } lv_sdl_cache_key_magic_t; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c index 4eb1940ef..b1ae6552a 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c @@ -11,100 +11,71 @@ #if LV_USE_GPU_STM32_DMA2D -#include LV_GPU_DMA2D_CMSIS_INCLUDE - /********************* * DEFINES *********************/ - #if LV_COLOR_16_SWAP - // TODO: F7 has red blue swap bit in control register for all layers and output - #error "Can't use DMA2D with LV_COLOR_16_SWAP 1" + // Note: DMA2D red/blue swap (RBS) works for all color modes + #define RBS_BIT 1U +#else + #define RBS_BIT 0U #endif -#if LV_COLOR_DEPTH == 8 - #error "Can't use DMA2D with LV_COLOR_DEPTH == 8" -#endif +#define CACHE_ROW_SIZE 32U // cache row size in Bytes + +// For code/implementation discussion refer to https://github.com/lvgl/lvgl/issues/3714#issuecomment-1365187036 +// astyle --options=lvgl/scripts/code-format.cfg --ignore-exclude-errors lvgl/src/draw/stm32_dma2d/*.c lvgl/src/draw/stm32_dma2d/*.h #if LV_COLOR_DEPTH == 16 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565 + const dma2d_color_format_t LvglColorFormat = RGB565; #elif LV_COLOR_DEPTH == 32 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888 + const dma2d_color_format_t LvglColorFormat = ARGB8888; #else - /*Can't use GPU with other formats*/ + #error "Cannot use DMA2D with LV_COLOR_DEPTH other than 16 or 32" #endif -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color); - - -static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa); - -static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); - - -static void invalidate_cache(void); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ +static bool isDma2dInProgess = false; // indicates whether DMA2D transfer *initiated here* is in progress /** * Turn on the peripheral and set output color mode, this only needs to be done once */ void lv_draw_stm32_dma2d_init(void) { - /*Enable DMA2D clock*/ + // Enable DMA2D clock #if defined(STM32F4) || defined(STM32F7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; // enable DMA2D #elif defined(STM32H7) RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN; #else # warning "LVGL can't enable the clock of DMA2D" #endif - /*Wait for hardware access to complete*/ + // Wait for hardware access to complete __asm volatile("DSB\n"); - /*Delay after setting peripheral clock*/ + // Delay after setting peripheral clock volatile uint32_t temp = RCC->AHB1ENR; LV_UNUSED(temp); - /*set output colour mode*/ - DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT; + // AHB master timer configuration + DMA2D->AMTCR = 0; // AHB bus guaranteed dead time disabled +#if defined(LV_STM32_DMA2D_TEST) + _lv_gpu_stm32_dwt_init(); // init µs timer +#endif } - void lv_draw_stm32_dma2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) { - lv_draw_sw_init_ctx(drv, draw_ctx); lv_draw_stm32_dma2d_ctx_t * dma2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; dma2d_draw_ctx->blend = lv_draw_stm32_dma2d_blend; - // dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded; - dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb; + dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded; + //dma2d_draw_ctx->base_draw.draw_img = lv_draw_stm32_dma2d_img; + // Note: currently it does not make sense use lv_gpu_stm32_dma2d_wait_cb() since waiting starts right after the dma2d transfer + //dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb; dma2d_draw_ctx->base_draw.buffer_copy = lv_draw_stm32_dma2d_buffer_copy; - } void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) @@ -113,153 +84,636 @@ void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ct LV_UNUSED(draw_ctx); } - -void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +static void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - lv_area_t blend_area; - if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; + if(dsc->blend_mode != LV_BLEND_MODE_NORMAL) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + // Note: x1 must be zero. Otherwise, there is no way to correctly calculate dest_stride. + //LV_ASSERT_MSG(draw_ctx->buf_area->x1 == 0); // critical? + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? - bool done = false; - - if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) { - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); - - lv_color_t * dest_buf = draw_ctx->buf; - dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); - - const lv_color_t * src_buf = dsc->src_buf; - if(src_buf) { - lv_draw_sw_blend_basic(draw_ctx, dsc); - lv_coord_t src_stride; - src_stride = lv_area_get_width(dsc->blend_area); - src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1); - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - lv_draw_stm32_dma2d_blend_map(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa); - done = true; - } - else if(dsc->opa >= LV_OPA_MAX) { - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - lv_draw_stm32_dma2d_blend_fill(dest_buf, dest_stride, &blend_area, dsc->color); - done = true; - } + if(dsc->src_buf) { + // For performance reasons, both source buffer start address and buffer size *should* be 32-byte aligned since source buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(dsc->blend_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)dsc->src_buf % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) } - if(!done) lv_draw_sw_blend_basic(draw_ctx, dsc); -} + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, dsc->blend_area, draw_ctx->clip_area)) return; + // + draw_ctx->buf_area has the entire draw buffer location + // + draw_ctx->clip_area has the current draw buffer location + // + dsc->blend_area has the location of the area intended to be painted - image etc. + // + draw_area has the area actually being painted + // All coordinates are relative to the screen. -void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, - void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, - void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area) -{ - LV_UNUSED(draw_ctx); - lv_draw_stm32_dma2d_blend_map(dest_buf, dest_area, dest_stride, src_buf, src_stride, LV_OPA_MAX); -} + const lv_opa_t * mask = dsc->mask_buf; + if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return; + else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; -static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format) -{ - /*TODO basic ARGB8888 image can be handles here*/ + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + if(mask != NULL) { + // For performance reasons, both mask buffer start address and buffer size *should* be 32-byte aligned since mask buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(dsc->mask_area) * sizeof(lv_opa_t); + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)mask % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, color_format); -} + lv_coord_t mask_stride = lv_area_get_width(dsc->mask_area); + lv_point_t mask_offset = lv_area_get_offset(dsc->mask_area, &draw_area); // mask offset in relation to draw_area -static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color) -{ - /*Simply fill an area*/ - int32_t area_w = lv_area_get_width(fill_area); - int32_t area_h = lv_area_get_height(fill_area); - invalidate_cache(); + if(dsc->src_buf == NULL) { // 93.5% + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_paint(draw_ctx->buf, dest_stride, &draw_area, mask, mask_stride, &mask_offset, dsc->color, + dsc->opa); + } + else { // 0.2% + // note: (x)RGB dsc->src_buf does not carry alpha channel bytes, + // alpha channel bytes are carried in dsc->mask_buf +#if LV_COLOR_DEPTH == 32 + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + lv_point_t src_offset = lv_area_get_offset(dsc->blend_area, &draw_area); // source image offset in relation to draw_area + lv_coord_t draw_width = lv_area_get_width(&draw_area); + lv_coord_t draw_height = lv_area_get_height(&draw_area); - DMA2D->CR = 0x30000; - DMA2D->OMAR = (uint32_t)dest_buf; - /*as input color mode is same as output we don't need to convert here do we?*/ - DMA2D->OCOLR = color.full; - DMA2D->OOR = dest_stride - area_w; - DMA2D->NLR = (area_w << DMA2D_NLR_PL_Pos) | (area_h << DMA2D_NLR_NL_Pos); + // merge mask alpha bytes with src RGB bytes + // TODO: optimize by reading 4 or 8 mask bytes at a time + mask += (mask_stride * mask_offset.y) + mask_offset.x; + lv_color_t * src_buf = (lv_color_t *)dsc->src_buf; + src_buf += (src_stride * src_offset.y) + src_offset.x; + uint16_t mask_buffer_offset = mask_stride - draw_width; + uint16_t src_buffer_offset = src_stride - draw_width; + while(draw_height > 0) { + draw_height--; + for(uint16_t x = 0; x < draw_width; x++) { + (*src_buf).ch.alpha = *mask; + src_buf++; + mask++; + } + mask += mask_buffer_offset; + src_buf += src_buffer_offset; + } - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, dsc->src_buf, src_stride, &src_offset, dsc->opa, + ARGB8888, false); +#else + // Note: 16-bit bitmap hardware blending with mask and background is possible, but requires a temp 24 or 32-bit buffer to combine bitmap with mask first. -} - - -static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa) -{ - - /*Simple copy*/ - int32_t dest_w = lv_area_get_width(dest_area); - int32_t dest_h = lv_area_get_height(dest_area); - - invalidate_cache(); - if(opa >= LV_OPA_MAX) { - DMA2D->CR = 0; - /*copy output colour mode, this register controls both input and output colour format*/ - DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->FGMAR = (uint32_t)src_buf; - DMA2D->FGOR = src_stride - dest_w; - DMA2D->OMAR = (uint32_t)dest_buf; - DMA2D->OOR = dest_stride - dest_w; - DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + lv_draw_sw_blend_basic(draw_ctx, dsc); // (e.g. Shop Items) + // clean cache after software drawing - this does not help since this is not the only place where buffer is written without dma2d + // lv_coord_t draw_width = lv_area_get_width(&draw_area); + // lv_coord_t draw_height = lv_area_get_height(&draw_area); + // uint32_t dest_address = (uint32_t)(draw_ctx->buf + (dest_stride * draw_area.y1) + draw_area.x1); + // _lv_gpu_stm32_dma2d_clean_cache(dest_address, dest_stride - draw_width, draw_width, draw_height, sizeof(lv_color_t)); +#endif + } } else { - DMA2D->CR = 0x20000; - - DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->BGMAR = (uint32_t)dest_buf; - DMA2D->BGOR = dest_stride - dest_w; - - DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT - /*alpha mode 2, replace with foreground * alpha value*/ - | (2 << DMA2D_FGPFCCR_AM_Pos) - /*alpha value*/ - | (opa << DMA2D_FGPFCCR_ALPHA_Pos); - DMA2D->FGMAR = (uint32_t)src_buf; - DMA2D->FGOR = src_stride - dest_w; - - DMA2D->OMAR = (uint32_t)dest_buf; - DMA2D->OOR = dest_stride - dest_w; - DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + if(dsc->src_buf == NULL) { // 6.1% + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_fill(draw_ctx->buf, dest_stride, &draw_area, dsc->color, dsc->opa); + } + else { // 0.2% + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + lv_point_t src_offset = lv_area_get_offset(dsc->blend_area, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, dsc->src_buf, src_stride, &src_offset, dsc->opa, + LvglColorFormat, true); + } } } -void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx) +// Does dest_area = intersect(draw_ctx->clip_area, src_area) ? +// See: https://github.com/lvgl/lvgl/issues/3714#issuecomment-1331710788 +static void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, void * dest_buf, lv_coord_t dest_stride, + const lv_area_t * dest_area, void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area) +{ + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? + // FIXME: + // 1. Both src_buf and dest_buf pixel size *must* be known to use DMA2D. + // 2. Verify both buffers start addresses and lengths are 32-byte (cache row size) aligned. + LV_UNUSED(draw_ctx); + lv_point_t src_offset = lv_area_get_offset(src_area, dest_area); + // FIXME: use lv_area_move(dest_area, -dest_area->x1, -dest_area->y1) here ? + // TODO: It is assumed that dest_buf and src_buf buffers are of lv_color_t type. Verify it, this assumption may be incorrect. + _lv_draw_stm32_dma2d_blend_map((const lv_color_t *)dest_buf, dest_stride, dest_area, (const lv_color_t *)src_buf, + src_stride, &src_offset, 0xff, LvglColorFormat, true); + // TODO: Investigate if output buffer cache needs to be invalidated. It depends on what the destination buffer is and how it is used next - by dma2d or not. + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); // TODO: is this line needed here? +} + +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t color_format) +{ + if(draw_ctx->draw_img_decoded == NULL) return; + lv_area_t draw_area; + lv_area_copy(&draw_area, draw_ctx->clip_area); + + bool mask_any = lv_draw_mask_is_any(&draw_area); + bool transform = img_dsc->angle != 0 || img_dsc->zoom != LV_IMG_ZOOM_NONE; + const dma2d_color_format_t bitmapColorFormat = lv_color_format_to_dma2d_color_format(color_format); + const bool ignoreBitmapAlpha = (color_format == LV_IMG_CF_RGBX8888); + + if(!mask_any && !transform && bitmapColorFormat != UNSUPPORTED && img_dsc->recolor_opa == LV_OPA_TRANSP) { + // simple bitmap blending, optionally with supported color format conversion - handle directly by dma2d + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + lv_coord_t src_stride = lv_area_get_width(coords); + lv_point_t src_offset = lv_area_get_offset(coords, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, src_buf, src_stride, &src_offset, + img_dsc->opa, bitmapColorFormat, ignoreBitmapAlpha); + } + else { + // all more complex cases which require additional image transformations + lv_draw_sw_img_decoded(draw_ctx, img_dsc, coords, src_buf, color_format); + + } +} + +static lv_point_t lv_area_get_offset(const lv_area_t * area1, const lv_area_t * area2) +{ + lv_point_t offset = {x: area2->x1 - area1->x1, y: area2->y1 - area1->y1}; + return offset; +} + +static dma2d_color_format_t lv_color_format_to_dma2d_color_format(lv_img_cf_t color_format) +{ + switch(color_format) { + case LV_IMG_CF_RGBA8888: + // note: LV_IMG_CF_RGBA8888 is actually ARGB8888 + return ARGB8888; + case LV_IMG_CF_RGBX8888: + // note: LV_IMG_CF_RGBX8888 is actually XRGB8888 + return ARGB8888; + case LV_IMG_CF_RGB565: + return RGB565; + case LV_IMG_CF_TRUE_COLOR: + return LvglColorFormat; + case LV_IMG_CF_TRUE_COLOR_ALPHA: +#if LV_COLOR_DEPTH == 16 + // bitmap color format is 24b ARGB8565 - dma2d unsupported + return UNSUPPORTED; +#elif LV_COLOR_DEPTH == 32 + return ARGB8888; +#else + // unknown bitmap color format + return UNSUPPORTED; +#endif + default: + return UNSUPPORTED; + } +} + +static lv_res_t lv_draw_stm32_dma2d_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * src_area, + const void * src) +{ + //if(lv_img_src_get_type(src) != LV_IMG_SRC_VARIABLE) return LV_RES_INV; + return LV_RES_INV; + if(img_dsc->opa <= LV_OPA_MIN) return LV_RES_OK; + const lv_img_dsc_t * img = src; + const dma2d_color_format_t bitmapColorFormat = lv_color_format_to_dma2d_color_format(img->header.cf); + const bool ignoreBitmapAlpha = (img->header.cf == LV_IMG_CF_RGBX8888); + + if(bitmapColorFormat == UNSUPPORTED || img_dsc->angle != 0 || img_dsc->zoom != LV_IMG_ZOOM_NONE) { + return LV_RES_INV; // sorry, dma2d can handle this + } + + // FIXME: handle dsc.pivot, dsc.recolor, dsc.blend_mode + // FIXME: src pixel size *must* be known to use DMA2D + // FIXME: If image is drawn by SW, then output cache needs to be cleaned next. Currently it is not possible. + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? + + // For performance reasons, both source buffer start address and buffer size *should* be 32-byte aligned since source buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(src_area) * sizeof(lv_color_t); // TODO: verify src pixel size = sizeof(lv_color_t) + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)src % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, src_area, draw_ctx->clip_area)) return LV_RES_OK; + + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + lv_point_t src_offset = lv_area_get_offset(src_area, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, img->data, img->header.w, + &src_offset, img_dsc->opa, bitmapColorFormat, ignoreBitmapAlpha); + return LV_RES_OK; +} + +static void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver && disp->driver->wait_cb) { - while(DMA2D->CR & DMA2D_CR_START_Msk) { - disp->driver->wait_cb(disp->driver); - } - } - else { - while(DMA2D->CR & DMA2D_CR_START_Msk); - } + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(disp->driver); lv_draw_sw_wait_for_finish(draw_ctx); - } /********************** * STATIC FUNCTIONS **********************/ -static void invalidate_cache(void) +/** + * @brief Fills draw_area with specified color. + * @param color color to be painted, note: alpha is ignored + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_fill(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa) { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver); - else { -#if __CORTEX_M >= 0x07 - if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk) - SCB_CleanInvalidateDCache(); + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + if(opa >= LV_OPA_MAX) { + DMA2D->CR = 0x3UL << DMA2D_CR_MODE_Pos; // Register-to-memory (no FG nor BG, only output stage active) + + DMA2D->OPFCCR = LvglColorFormat; + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; // out buffer offset + // Note: unlike FGCOLR and BGCOLR, OCOLR bits must match DMA2D_OUTPUT_COLOR, alpha can be specified +#if RBS_BIT + // swap red/blue bits + DMA2D->OCOLR = (color.ch.blue << 11) | (color.ch.green_l << 5 | color.ch.green_h << 8) | (color.ch.red); +#else + DMA2D->OCOLR = color.full; #endif } + else { + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + + DMA2D->FGPFCCR = A8; + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + // Alpha Mode 1: Replace original foreground image alpha channel value by FGPFCCR.ALPHA + DMA2D->FGPFCCR |= (0x1UL << DMA2D_FGPFCCR_AM_Pos); + //DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + + // Note: in Alpha Mode 1 FGMAR and FGOR are not used to supply foreground A8 bytes, + // those bytes are replaced by constant ALPHA defined in FGPFCCR + DMA2D->FGMAR = (uint32_t)dest_buf; + DMA2D->FGOR = dest_stride; + DMA2D->FGCOLR = lv_color_to32(color) & 0x00ffffff; // swap FGCOLR R/B bits if FGPFCCR.RBS (RBS_BIT) bit is set + + DMA2D->BGPFCCR = LvglColorFormat; + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); + DMA2D->BGMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->BGOR = dest_stride - draw_width; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + + DMA2D->OPFCCR = LvglColorFormat; + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); + DMA2D->OMAR = DMA2D->BGMAR; + DMA2D->OOR = DMA2D->BGOR; + DMA2D->OCOLR = 0; + } + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Draws src (foreground) map on dst (background) map. + * @param src_offset src offset in relation to dst, useful when src is larger than draw_area + * @param opa constant opacity to be applied + * @param bitmapColorCode bitmap color type + * @param ignoreAlpha if TRUE, bitmap src alpha channel is ignored + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_map(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const void * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset, lv_opa_t opa, + dma2d_color_format_t src_color_format, bool ignore_src_alpha) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + if(opa <= LV_OPA_MIN || src_color_format == UNSUPPORTED) return; + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + bool bitmapHasOpacity = !ignore_src_alpha && (src_color_format == ARGB8888 || src_color_format == ARGB1555 || + src_color_format == ARGB4444); + + if(opa >= LV_OPA_MAX) opa = 0xff; + + uint8_t srcBpp; // source bytes per pixel + switch(src_color_format) { + case ARGB8888: + srcBpp = 4; + break; + case RGB888: + srcBpp = 3; + break; + case RGB565: + case ARGB1555: + case ARGB4444: + srcBpp = 2; + break; + default: + LV_LOG_ERROR("unsupported color format"); + return; + } + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->FGPFCCR = src_color_format; + + if(opa == 0xff && !bitmapHasOpacity) { + // no need to blend + if(src_color_format == LvglColorFormat) { + // no need to convert pixel format (PFC) either + DMA2D->CR = 0x0UL; + } + else { + DMA2D->CR = 0x1UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with PFC (FG fetch only with FG PFC active) + } + // Alpha Mode 0: No modification of the foreground image alpha channel value + } + else { + // blend + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + if(bitmapHasOpacity) { + // Alpha Mode 2: Replace original foreground image alpha channel value by FGPFCCR.ALPHA multiplied with original alpha channel value + DMA2D->FGPFCCR |= (0x2UL << DMA2D_FGPFCCR_AM_Pos); + } + else { + // Alpha Mode 1: Replace original foreground image alpha channel value by FGPFCCR.ALPHA + DMA2D->FGPFCCR |= (0x1UL << DMA2D_FGPFCCR_AM_Pos); + } + } + + DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + DMA2D->FGMAR = ((uint32_t)src_buf) + srcBpp * ((src_stride * src_offset->y) + src_offset->x); + DMA2D->FGOR = src_stride - draw_width; + DMA2D->FGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, srcBpp); + + DMA2D->OPFCCR = LvglColorFormat; + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; + DMA2D->OCOLR = 0; + + if(opa != 0xff || bitmapHasOpacity) { + // use background (BG*) registers + DMA2D->BGPFCCR = LvglColorFormat; + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); + DMA2D->BGMAR = DMA2D->OMAR; + DMA2D->BGOR = DMA2D->OOR; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + } + + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Paints solid color with alpha mask with additional constant opacity. Useful e.g. for painting anti-aliased fonts. + * @param src_offset src offset in relation to dst, useful when src (alpha mask) is larger than draw_area + * @param color color to paint, note: alpha is ignored + * @param opa constant opacity to be applied + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_paint(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_opa_t * mask_buf, lv_coord_t mask_stride, const lv_point_t * mask_offset, + lv_color_t color, lv_opa_t opa) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + + DMA2D->FGPFCCR = A8; + if(opa < LV_OPA_MAX) { + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + DMA2D->FGPFCCR |= (0x2UL << + DMA2D_FGPFCCR_AM_Pos); // Alpha Mode: Replace original foreground image alpha channel value by FGPFCCR.ALPHA multiplied with original alpha channel value + } + //DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + DMA2D->FGMAR = (uint32_t)(mask_buf + (mask_stride * mask_offset->y) + mask_offset->x); + DMA2D->FGOR = mask_stride - draw_width; + DMA2D->FGCOLR = lv_color_to32(color) & 0x00ffffff; // swap FGCOLR R/B bits if FGPFCCR.RBS (RBS_BIT) bit is set + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, sizeof(lv_opa_t)); + + DMA2D->BGPFCCR = LvglColorFormat; + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); + DMA2D->BGMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->BGOR = dest_stride - draw_width; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + + DMA2D->OPFCCR = LvglColorFormat; + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); + DMA2D->OMAR = DMA2D->BGMAR; + DMA2D->OOR = DMA2D->BGOR; + DMA2D->OCOLR = 0; + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Copies src (foreground) map to the dst (background) map. + * @param src_offset src offset in relation to dst, useful when src is larger than draw_area + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_copy_buffer(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_color_t * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->CR = 0x0UL; // Memory-to-memory (FG fetch only) + + DMA2D->FGPFCCR = LvglColorFormat; + DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + DMA2D->FGMAR = (uint32_t)(src_buf + (src_stride * src_offset->y) + src_offset->x); + DMA2D->FGOR = src_stride - draw_width; + DMA2D->FGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, sizeof(lv_color_t)); + + // Note BG* registers do not need to be set up since BG is not used + + DMA2D->OPFCCR = LvglColorFormat; + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; + DMA2D->OCOLR = 0; + + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_start_dma_transfer(void) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); + isDma2dInProgess = true; + DMA2D->IFCR = 0x3FU; // trigger ISR flags reset + // Note: cleaning output buffer cache is needed only when buffer may be misaligned or adjacent area may have been drawn in sw-fashion, e.g. using lv_draw_sw_blend_basic() +#if LV_COLOR_DEPTH == 16 + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->OMAR, DMA2D->OOR, (DMA2D->NLR & DMA2D_NLR_PL_Msk) >> DMA2D_NLR_PL_Pos, + (DMA2D->NLR & DMA2D_NLR_NL_Msk) >> DMA2D_NLR_NL_Pos, sizeof(lv_color_t)); +#endif + DMA2D->CR |= DMA2D_CR_START; + // Note: for some reason mask buffer gets damaged during transfer if waiting is postponed + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); // FIXME: this line should not be needed here, but it is +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_await_dma_transfer_finish(lv_disp_drv_t * disp_drv) +{ + if(disp_drv && disp_drv->wait_cb) { + while((DMA2D->CR & DMA2D_CR_START) != 0U) { + disp_drv->wait_cb(disp_drv); + } + } + else { + while((DMA2D->CR & DMA2D_CR_START) != 0U); + } + + __IO uint32_t isrFlags = DMA2D->ISR; + + if(isrFlags & DMA2D_ISR_CEIF) { + LV_LOG_ERROR("DMA2D config error"); + } + + if(isrFlags & DMA2D_ISR_TEIF) { + LV_LOG_ERROR("DMA2D transfer error"); + } + + DMA2D->IFCR = 0x3FU; // trigger ISR flags reset + + if(isDma2dInProgess) { + // invalidate output buffer cached memory ONLY after DMA2D transfer + //_lv_gpu_stm32_dma2d_invalidate_cache(DMA2D->OMAR, DMA2D->OOR, (DMA2D->NLR & DMA2D_NLR_PL_Msk) >> DMA2D_NLR_PL_Pos, (DMA2D->NLR & DMA2D_NLR_NL_Msk) >> DMA2D_NLR_NL_Pos, sizeof(lv_color_t)); + isDma2dInProgess = false; + } +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_invalidate_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size) +{ + if(((SCB->CCR) & SCB_CCR_DC_Msk) == 0) return; // L1 data cache is disabled + uint16_t stride = pixel_size * (width + offset); // in bytes + uint16_t ll = pixel_size * width; // line length in bytes + uint32_t n = 0; // address of the next cache row after the last invalidated row + lv_coord_t h = 0; + + __DSB(); + + while(h < height) { + uint32_t a = address + (h * stride); + uint32_t e = a + ll; // end address, address of the first byte after the current line + a &= ~(CACHE_ROW_SIZE - 1U); + if(a < n) a = n; // prevent the previous last cache row from being invalidated again + + while(a < e) { + SCB->DCIMVAC = a; + a += CACHE_ROW_SIZE; + } + + n = a; + h++; + }; + + __DSB(); + __ISB(); +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_clean_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size) +{ + if(((SCB->CCR) & SCB_CCR_DC_Msk) == 0) return; // L1 data cache is disabled + uint16_t stride = pixel_size * (width + offset); // in bytes + uint16_t ll = pixel_size * width; // line length in bytes + uint32_t n = 0; // address of the next cache row after the last cleaned row + lv_coord_t h = 0; + __DSB(); + + while(h < height) { + uint32_t a = address + (h * stride); + uint32_t e = a + ll; // end address, address of the first byte after the current line + a &= ~(CACHE_ROW_SIZE - 1U); + if(a < n) a = n; // prevent the previous last cache row from being cleaned again + + while(a < e) { + SCB->DCCMVAC = a; + a += CACHE_ROW_SIZE; + } + + n = a; + h++; + }; + + __DSB(); + __ISB(); +} + +// initialize µs timer +LV_STM32_DMA2D_STATIC bool _lv_gpu_stm32_dwt_init(void) +{ + // disable TRC + CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; + // enable TRC + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + + DWT->LAR = 0xC5ACCE55; + + // disable clock cycle counter + DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; + // enable clock cycle counter + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + // reset the clock cycle counter value + DWT->CYCCNT = 0; + + // 3 NO OPERATION instructions + __ASM volatile("NOP"); + __ASM volatile("NOP"); + __ASM volatile("NOP"); + + // check if clock cycle counter has started + if(DWT->CYCCNT) { + return true; // clock cycle counter started + } + else { + return false; // clock cycle counter not started + } +} + +// get elapsed µs since reset +LV_STM32_DMA2D_STATIC uint32_t _lv_gpu_stm32_dwt_get_us(void) +{ + uint32_t us = (DWT->CYCCNT * 1000000) / HAL_RCC_GetHCLKFreq(); + return us; +} + +// reset µs timer +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dwt_reset(void) +{ + DWT->CYCCNT = 0; } #endif diff --git a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h index fa7070e2a..5ecce6deb 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h @@ -10,52 +10,83 @@ extern "C" { #endif -/********************* - * INCLUDES - *********************/ #include "../../misc/lv_color.h" #include "../../hal/lv_hal_disp.h" #include "../sw/lv_draw_sw.h" #if LV_USE_GPU_STM32_DMA2D +/********************* + * INCLUDES + *********************/ +#include LV_GPU_DMA2D_CMSIS_INCLUDE + /********************* * DEFINES *********************/ - -#define LV_DMA2D_ARGB8888 0 -#define LV_DMA2D_RGB888 1 -#define LV_DMA2D_RGB565 2 -#define LV_DMA2D_ARGB1555 3 -#define LV_DMA2D_ARGB4444 4 +#if defined(LV_STM32_DMA2D_TEST) +// removes "static" modifier for some internal methods in order to test them +#define LV_STM32_DMA2D_STATIC +#else +#define LV_STM32_DMA2D_STATIC static +#endif /********************** * TYPEDEFS **********************/ +enum dma2d_color_format { + ARGB8888 = 0x0, + RGB888 = 0x01, + RGB565 = 0x02, + ARGB1555 = 0x03, + ARGB4444 = 0x04, + A8 = 0x09, + UNSUPPORTED = 0xff, +}; +typedef enum dma2d_color_format dma2d_color_format_t; typedef lv_draw_sw_ctx_t lv_draw_stm32_dma2d_ctx_t; - struct _lv_disp_drv_t; /********************** * GLOBAL PROTOTYPES **********************/ - -/** - * Turn on the peripheral and set output color mode, this only needs to be done once - */ void lv_draw_stm32_dma2d_init(void); - void lv_draw_stm32_dma2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); - void lv_draw_stm32_dma2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +static void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); +static void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, + void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, + void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); +static lv_res_t lv_draw_stm32_dma2d_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * src_area, const void * src); +static void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t color_format); +static dma2d_color_format_t lv_color_format_to_dma2d_color_format(lv_img_cf_t color_format); +static lv_point_t lv_area_get_offset(const lv_area_t * area1, const lv_area_t * area2); -void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); - -void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, - void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, - void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); - -void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); +/********************** + * STATIC PROTOTYPES + **********************/ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_fill(const lv_color_t * dst_buf, lv_coord_t dst_stride, + const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_map(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const void * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset, lv_opa_t opa, + dma2d_color_format_t src_color_format, bool ignore_src_alpha); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_paint(const lv_color_t * dst_buf, lv_coord_t dst_stride, + const lv_area_t * draw_area, const lv_opa_t * mask_buf, lv_coord_t mask_stride, const lv_point_t * mask_offset, + lv_color_t color, lv_opa_t opa); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_copy_buffer(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_color_t * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_await_dma_transfer_finish(lv_disp_drv_t * disp_drv); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_start_dma_transfer(void); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_invalidate_cache(uint32_t address, lv_coord_t offset, + lv_coord_t width, lv_coord_t height, uint8_t pixel_size); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_clean_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size); +LV_STM32_DMA2D_STATIC bool _lv_gpu_stm32_dwt_init(void); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dwt_reset(void); +LV_STM32_DMA2D_STATIC uint32_t _lv_gpu_stm32_dwt_get_us(void); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c index 428aba62c..bff0a8f19 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c @@ -103,7 +103,7 @@ void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * d LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - const lv_opa_t * mask; + lv_opa_t * mask; if(dsc->mask_buf == NULL) mask = NULL; if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return; else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; @@ -129,7 +129,6 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons } } - const lv_color_t * src_buf = dsc->src_buf; lv_coord_t src_stride; if(src_buf) { @@ -142,8 +141,18 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons lv_coord_t mask_stride; if(mask) { + /*Round the values in the mask if anti-aliasing is disabled*/ + if(disp->driver->antialiasing == 0) { + int32_t mask_size = lv_area_get_size(dsc->mask_area); + int32_t i; + for(i = 0; i < mask_size; i++) { + mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP; + } + } + mask_stride = lv_area_get_width(dsc->mask_area); mask += mask_stride * (blend_area.y1 - dsc->mask_area->y1) + (blend_area.x1 - dsc->mask_area->x1); + } else { mask_stride = 0; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c index 9522888c9..7caa74912 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c @@ -489,8 +489,8 @@ static void draw_letter_subpx(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_ #endif #if LV_FONT_SUBPX_BGR - res_color.ch.blue = (uint32_t)((uint32_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; - res_color.ch.red = (uint32_t)((uint32_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; + res_color.ch.red = (uint32_t)((uint16_t)txt_rgb[0] * font_rgb[2] + (bg_rgb[0] * (255 - font_rgb[2]))) >> 8; + res_color.ch.blue = (uint32_t)((uint16_t)txt_rgb[2] * font_rgb[0] + (bg_rgb[2] * (255 - font_rgb[0]))) >> 8; #else res_color.ch.red = (uint32_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; res_color.ch.blue = (uint32_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c index 80b1e6dea..204503a4f 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c @@ -122,8 +122,8 @@ void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, xs_step_256 = (256 * xs_diff) / (dest_w - 1); ys_step_256 = (256 * ys_diff) / (dest_w - 1); } - int32_t xs_ups = xs1_ups; - int32_t ys_ups = ys1_ups; + int32_t xs_ups = xs1_ups + 0x80; + int32_t ys_ups = ys1_ups + 0x80; if(draw_dsc->antialias == 0) { switch(cf) { @@ -180,7 +180,7 @@ static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, l } else { -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 const uint8_t * src_tmp = src; src_tmp += ys_int * src_stride + xs_int; cbuf[x].full = src_tmp[0]; @@ -221,7 +221,7 @@ static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, const uint8_t * src_tmp = src; src_tmp += (ys_int * src_stride * LV_IMG_PX_SIZE_ALPHA_BYTE) + xs_int * LV_IMG_PX_SIZE_ALPHA_BYTE; -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 cbuf[x].full = src_tmp[0]; #elif LV_COLOR_DEPTH == 16 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8); @@ -396,7 +396,7 @@ static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t sr if(abuf[x] == 0x00) continue; -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 c_base.full = px_base[0]; c_ver.full = px_ver[0]; c_hor.full = px_hor[0]; @@ -429,7 +429,7 @@ static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t sr } /*Partially out of the image*/ else { -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 cbuf[x].full = src_tmp[0]; #elif LV_COLOR_DEPTH == 16 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c b/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c index 405a56b7f..a53c95e88 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c @@ -470,8 +470,14 @@ static void children_repos(lv_obj_t * cont, flex_t * f, int32_t item_first_id, i } } - if(f->row) item->w_layout = 1; - else item->h_layout = 1; + if(f->row) { + item->w_layout = 1; + item->h_layout = 0; + } + else { + item->h_layout = 1; + item->w_layout = 0; + } if(s != area_get_main_size(&item->coords)) { lv_obj_invalidate(item); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c b/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c index 4eec637bd..505a977b8 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c @@ -217,6 +217,7 @@ static void gridnav_event_cb(lv_event_t * e) if(dsc->focused_obj == NULL) dsc->focused_obj = find_first_focusable(obj); if(dsc->focused_obj) { lv_obj_add_state(dsc->focused_obj, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY); + lv_obj_clear_state(dsc->focused_obj, LV_STATE_PRESSED); /*Be sure the focuses obj is not stuck in pressed state*/ lv_obj_scroll_to_view(dsc->focused_obj, LV_ANIM_OFF); } } diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.c b/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.c old mode 100755 new mode 100644 diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.h b/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.h old mode 100755 new mode 100644 diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h index 11a55b5a7..96f08aa24 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h +++ b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h @@ -105,6 +105,17 @@ void * lv_msg_get_user_data(lv_msg_t * m); */ lv_msg_t * lv_event_get_msg(lv_event_t * e); +/*Fix typo*/ +static inline void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data) +{ + return lv_msg_subsribe(msg_id, cb, user_data); +} + +static inline void * lv_msg_subscribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data) +{ + return lv_msg_subsribe_obj(msg_id, obj, user_data); +} + /********************** * GLOBAL VARIABLES **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c index 135a8a4ba..072d02e05 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c @@ -64,7 +64,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent) return obj; } -void lv_animimg_set_src(lv_obj_t * obj, lv_img_dsc_t * dsc[], uint8_t num) +void lv_animimg_set_src(lv_obj_t * obj, const void * dsc[], uint8_t num) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_animimg_t * animimg = (lv_animimg_t *)obj; diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h index 632949477..0ba01f239 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h @@ -37,7 +37,7 @@ typedef struct { lv_img_t img; lv_anim_t anim; /*picture sequence */ - lv_img_dsc_t ** dsc; + const void ** dsc; int8_t pic_count; } lv_animimg_t; @@ -69,7 +69,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent); * @param dsc pointer to a series images * @param num images' number */ -void lv_animimg_set_src(lv_obj_t * img, lv_img_dsc_t * dsc[], uint8_t num); +void lv_animimg_set_src(lv_obj_t * img, const void * dsc[], uint8_t num); /** * Startup the image animation. diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c index da6c18c0e..c5afb8b94 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c @@ -1182,7 +1182,6 @@ static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) const lv_area_t * clip_area_ori = draw_ctx->clip_area; draw_ctx->clip_area = &clip_area; - lv_chart_t * chart = (lv_chart_t *)obj; uint16_t i; @@ -1200,6 +1199,7 @@ static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) int32_t ser_gap = ((int32_t)lv_obj_get_style_pad_column(obj, LV_PART_ITEMS) * chart->zoom_x) >> 8; /*Gap between the columns on the ~same X*/ lv_coord_t col_w = (block_w - (ser_cnt - 1) * ser_gap) / ser_cnt; + if(col_w < 1) col_w = 1; lv_coord_t border_w = lv_obj_get_style_border_width(obj, LV_PART_MAIN); lv_coord_t x_ofs = pad_left - lv_obj_get_scroll_left(obj) + border_w; @@ -1531,16 +1531,16 @@ static void draw_x_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis lv_coord_t label_gap; if(axis == LV_CHART_AXIS_PRIMARY_X) { label_gap = t->label_en ? lv_obj_get_style_pad_bottom(obj, LV_PART_TICKS) : 0; - y_ofs = obj->coords.y2; + y_ofs = obj->coords.y2 + 1; } else { label_gap = t->label_en ? lv_obj_get_style_pad_top(obj, LV_PART_TICKS) : 0; - y_ofs = obj->coords.y1; + y_ofs = obj->coords.y1 - 1; } if(axis == LV_CHART_AXIS_PRIMARY_X) { if(y_ofs > draw_ctx->clip_area->y2) return; - if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < draw_ctx->clip_area->y1) return; + if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < draw_ctx->clip_area->y1) return; } lv_draw_line_dsc_t line_dsc; @@ -1634,7 +1634,6 @@ static void draw_x_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); } - if(p1.x + line_dsc.width / 2 >= obj->coords.x1 && p2.x - line_dsc.width / 2 <= obj->coords.x2) { lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c index 668ab97e9..1e651b572 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c @@ -612,6 +612,7 @@ static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area if(angle > 3600) angle -= 3600; img_dsc.angle = angle; + part_draw_dsc.id = LV_METER_DRAW_PART_NEEDLE_IMG; part_draw_dsc.img_dsc = &img_dsc; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); diff --git a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c index 0dd8f6b30..10640a28a 100644 --- a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c +++ b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c @@ -23,9 +23,8 @@ #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" #include "../draw/swm341_dma2d/lv_gpu_swm341_dma2d.h" #include "../draw/arm2d/lv_gpu_arm2d.h" -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - #include "../draw/nxp/lv_gpu_nxp.h" -#endif +#include "../draw/nxp/vglite/lv_draw_vglite.h" +#include "../draw/nxp/pxp/lv_draw_pxp.h" #if LV_USE_THEME_DEFAULT #include "../extra/themes/default/lv_theme_default.h" @@ -105,10 +104,14 @@ void lv_disp_drv_init(lv_disp_drv_t * driver) driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init; driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_init; driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t); -#elif LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - driver->draw_ctx_init = lv_draw_nxp_ctx_init; - driver->draw_ctx_deinit = lv_draw_nxp_ctx_deinit; - driver->draw_ctx_size = sizeof(lv_draw_nxp_ctx_t); +#elif LV_USE_GPU_NXP_VG_LITE + driver->draw_ctx_init = lv_draw_vglite_ctx_init; + driver->draw_ctx_deinit = lv_draw_vglite_ctx_deinit; + driver->draw_ctx_size = sizeof(lv_draw_vglite_ctx_t); +#elif LV_USE_GPU_NXP_PXP + driver->draw_ctx_init = lv_draw_pxp_ctx_init; + driver->draw_ctx_deinit = lv_draw_pxp_ctx_deinit; + driver->draw_ctx_size = sizeof(lv_draw_pxp_ctx_t); #elif LV_USE_GPU_SDL driver->draw_ctx_init = lv_draw_sdl_init_ctx; driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx; diff --git a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h index ca51a08c2..5bbcf530e 100644 --- a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h +++ b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h @@ -141,6 +141,7 @@ typedef struct _lv_indev_proc_t { struct { /*Pointer and button data*/ lv_point_t act_point; /**< Current point of input device.*/ + lv_point_t indev_point; lv_point_t last_point; /**< Last point of input device.*/ lv_point_t last_raw_point; /**< Last point read from read_cb. */ lv_point_t vect; /**< Difference between `act_point` and `last_point`.*/ diff --git a/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h b/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h index 97807fe37..80b9b86cf 100644 --- a/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h +++ b/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h @@ -253,6 +253,9 @@ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ #endif #endif + /*If using lvgl as ESP32 component*/ + // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" + // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. diff --git a/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h b/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h index 1792dae88..5cf0b19c1 100644 --- a/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h +++ b/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h @@ -70,11 +70,6 @@ LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE); #endif // *INDENT-ON* -/** On simple system, don't waste resources on gradients */ -#if !defined(LV_DRAW_COMPLEX) || !defined(LV_GRADIENT_MAX_STOPS) -#define LV_GRADIENT_MAX_STOPS 2 -#endif - #define LV_STYLE_PROP_META_INHERIT 0x8000 #define LV_STYLE_PROP_META_INITIAL 0x4000 #define LV_STYLE_PROP_META_MASK (LV_STYLE_PROP_META_INHERIT | LV_STYLE_PROP_META_INITIAL) diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c index fd9b3948f..f79e88274 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c @@ -477,6 +477,7 @@ static void draw_main(lv_event_t * e) area_ok = _lv_area_intersect(&mask_sel, draw_ctx->clip_area, &sel_area); if(area_ok) { lv_obj_t * label = get_label(obj); + if(lv_label_get_recolor(label)) label_dsc.flag |= LV_TEXT_FLAG_RECOLOR; /*Get the size of the "selected text"*/ lv_point_t res_p; @@ -529,6 +530,8 @@ static void draw_label(lv_event_t * e) lv_draw_label_dsc_t label_draw_dsc; lv_draw_label_dsc_init(&label_draw_dsc); lv_obj_init_draw_label_dsc(roller, LV_PART_MAIN, &label_draw_dsc); + if(lv_label_get_recolor(label_obj)) label_draw_dsc.flag |= LV_TEXT_FLAG_RECOLOR; + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); /*If the roller has shadow or outline it has some ext. draw size diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c index 5ff65ab23..f789e8d33 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c @@ -42,6 +42,7 @@ static lv_res_t get_pressed_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col) static size_t get_cell_txt_len(const char * txt); static void copy_cell_txt(char * dst, const char * txt); static void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t * area); +static void scroll_to_selected_cell(lv_obj_t * obj); static inline bool is_cell_empty(void * cell) { @@ -516,6 +517,7 @@ static void lv_table_event(const lv_obj_class_t * class_p, lv_event_t * e) if(col == LV_TABLE_CELL_NONE || row == LV_TABLE_CELL_NONE) { table->col_act = 0; table->row_act = 0; + scroll_to_selected_cell(obj); lv_obj_invalidate(obj); return; } @@ -560,6 +562,8 @@ static void lv_table_event(const lv_obj_class_t * class_p, lv_event_t * e) table->row_act = row; lv_obj_invalidate(obj); + scroll_to_selected_cell(obj); + res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); if(res != LV_RES_OK) return; } @@ -1004,4 +1008,26 @@ static void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t } + +static void scroll_to_selected_cell(lv_obj_t * obj) +{ + lv_table_t * table = (lv_table_t *)obj; + + lv_area_t a; + get_cell_area(obj, table->row_act, table->col_act, &a); + if(a.x1 < 0) { + lv_obj_scroll_by_bounded(obj, -a.x1, 0, LV_ANIM_ON); + } + else if(a.x2 > lv_obj_get_width(obj)) { + lv_obj_scroll_by_bounded(obj, lv_obj_get_width(obj) - a.x2, 0, LV_ANIM_ON); + } + + if(a.y1 < 0) { + lv_obj_scroll_by_bounded(obj, 0, -a.y1, LV_ANIM_ON); + } + else if(a.y2 > lv_obj_get_height(obj)) { + lv_obj_scroll_by_bounded(obj, 0, lv_obj_get_height(obj) - a.y2, LV_ANIM_ON); + } + +} #endif