ESP32 LVGL library from v8.3.3 to v8.3.5 (no functional change) (#18128)

This commit is contained in:
s-hadinger 2023-03-06 21:04:02 +02:00 committed by GitHub
parent af8dbe8724
commit 215838db1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 3984 additions and 1992 deletions

View File

@ -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)

View File

@ -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": {

View File

@ -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

View File

@ -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.

View File

@ -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 ""
/*********************

View File

@ -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.

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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, \
&copy_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,
&copy_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,
&copy_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,
&copy_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,
&copy_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,
&copy_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,
&copy_size,
0xFF,
blend_dsc.opa);
__arm_2d_impl_src_msk_copy(
(color_int *)src_buf_tmp,
src_stride,
mask_temp_buf,
src_stride,
&copy_size,
(color_int *)dest_buf,
dest_stride,
&copy_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,
&copy_size,
(color_int *)dest_buf,
dest_stride,
&copy_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);

View File

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

View File

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

View File

@ -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

View File

@ -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*/

View File

@ -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

View File

@ -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*/

View File

@ -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*/

View File

@ -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*/

View File

@ -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

View File

@ -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)

View File

@ -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
**********************/

View File

@ -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) {
}

View File

@ -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

View File

@ -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 <math.h>
#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*/

View File

@ -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*/

View File

@ -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 <math.h>
/*********************
* 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;

View File

@ -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

View File

@ -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*/

View File

@ -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

View File

@ -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 <math.h>
/*********************
* 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*/

View File

@ -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*/

View File

@ -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 <math.h>
/*********************
* 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
**********************/

View File

@ -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

View File

@ -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*/

View File

@ -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*/

View File

@ -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*/

View File

@ -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*/

View File

@ -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*/

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

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

View File

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

View File

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

View File

View File

View File

@ -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
**********************/

View File

@ -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;

View File

@ -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.

View File

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

View File

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

View File

@ -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;

View File

@ -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`.*/

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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