1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00

feat(vglite, pxp): add beta version of NXP's PXP and VG-Lite acceleration (#4568)

Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com>
This commit is contained in:
nicusorcitu 2023-09-20 13:32:24 +03:00 committed by GitHub
parent 97dad61dd8
commit 733e11d86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 5841 additions and 17 deletions

20
Kconfig
View File

@ -298,23 +298,11 @@ menu "LVGL configuration"
Must be defined to include path of CMSIS header of target processor
e.g. "SWM341.h"
config LV_USE_GPU_NXP_PXP
bool "Use NXP's PXP GPU iMX RTxxx platforms."
config LV_USE_GPU_NXP_PXP_AUTO_INIT
bool "Call lv_gpu_nxp_pxp_init() automatically or manually."
depends on LV_USE_GPU_NXP_PXP
help
1: Add default bare metal and FreeRTOS interrupt handling
routines for PXP (lv_gpu_nxp_pxp_osa.c) and call
lv_gpu_nxp_pxp_init() automatically during lv_init().
Note that symbol SDK_OS_FREE_RTOS has to be defined in order
to use FreeRTOS OSA, otherwise bare-metal implementation is
selected.
0: lv_gpu_nxp_pxp_init() has to be called manually before
lv_init().
config LV_USE_DRAW_VGLITE
bool "Use NXP's VG-Lite GPU on iMX RTxxx platforms."
config LV_USE_GPU_NXP_VG_LITE
bool "Use NXP's VG-Lite GPU iMX RTxxx platforms."
config LV_USE_DRAW_PXP
bool "Use NXP's PXP on iMX RTxxx platforms."
config LV_USE_GPU_SDL
bool "Use SDL renderer API"

View File

@ -123,6 +123,12 @@
#endif
#endif
/* Use NXP's VG-Lite GPU on iMX RTxxx platforms. */
#define LV_USE_DRAW_VGLITE 0
/* Use NXP's PXP on iMX RTxxx platforms. */
#define LV_USE_DRAW_PXP 0
/*=================
* OPERATING SYSTEM
*=================*/

View File

@ -18,7 +18,6 @@
#include "../draw/sw/lv_draw_sw.h"
#endif
/*********************
* DEFINES
*********************/

View File

@ -0,0 +1,99 @@
/**
* @file lv_draw_buf_pxp.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_cfg.h"
#include "lv_pxp_utils.h"
#include "lvgl_support.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area);
static void _pxp_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area,
void * src_buf, uint32_t src_stride, const lv_area_t * src_area, lv_color_format_t cf);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_buf_pxp_init_handlers(void)
{
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
handlers->invalidate_cache_cb = _invalidate_cache;
handlers->buf_copy_cb = _pxp_buf_copy;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area)
{
LV_UNUSED(draw_buf);
LV_UNUSED(area);
DEMO_CleanInvalidateCache();
}
void _pxp_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area,
void * src_buf, uint32_t src_stride, const lv_area_t * src_area,
lv_color_format_t cf)
{
lv_pxp_reset();
const pxp_pic_copy_config_t picCopyConfig = {
.srcPicBaseAddr = (uint32_t)src_buf,
.srcPitchBytes = src_stride,
.srcOffsetX = src_area->x1,
.srcOffsetY = src_area->y1,
.destPicBaseAddr = (uint32_t)dest_buf,
.destPitchBytes = dest_stride,
.destOffsetX = dest_area->x1,
.destOffsetY = dest_area->y1,
.width = lv_area_get_width(src_area),
.height = lv_area_get_height(src_area),
.pixelFormat = pxp_get_as_px_format(cf)
};
PXP_StartPictureCopy(PXP_ID, &picCopyConfig);
lv_pxp_run();
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,317 @@
/**
* @file lv_draw_pxp.c
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_cfg.h"
#include "../../../display/lv_display_private.h"
/*********************
* DEFINES
*********************/
#define DRAW_UNIT_ID_PXP 3
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/*
* Dispatch a task to the PXP unit.
* Return 1 if task was dispatched, 0 otherwise (task not supported).
*/
static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
/*
* Evaluate a task and set the score and preferred PXP unit.
* Return 1 if task is preferred, 0 otherwise (task is not supported).
*/
static int32_t _pxp_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
#if LV_USE_OS
static void _pxp_render_thread_cb(void * ptr);
#endif
static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u);
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_init(void)
{
lv_draw_buf_pxp_init_handlers();
lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t));
draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch;
draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate;
lv_pxp_init();
#if LV_USE_OS
lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 8 * 1024, draw_pxp_unit);
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
static inline bool _pxp_cf_supported(lv_color_format_t cf)
{
bool is_cf_supported = (cf == LV_COLOR_FORMAT_RGB565 || cf == LV_COLOR_FORMAT_RGB888 ||
cf == LV_COLOR_FORMAT_ARGB8888 || cf == LV_COLOR_FORMAT_XRGB8888);
return is_cf_supported;
}
static bool _pxp_draw_img_supported(const lv_draw_image_dsc_t * draw_dsc)
{
const lv_image_dsc_t * img_dsc = draw_dsc->src;
bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP);
bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->zoom != LV_SCALE_NONE);
/* Recolor and transformation are not supported at the same time. */
if(has_recolor && has_transform)
return false;
bool has_opa = (draw_dsc->opa < (lv_opa_t)LV_OPA_MAX);
bool src_has_alpha = (img_dsc->header.cf == LV_COLOR_FORMAT_ARGB8888);
/*
* Recolor or transformation for images w/ opa or alpha channel can't
* be obtained in a single PXP configuration. Two steps are required.
*/
if((has_recolor || has_transform) && (has_opa || src_has_alpha))
return false;
/* PXP can only rotate at 90x angles. */
if(draw_dsc->rotation % 900)
return false;
/*
* 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.
*
* No combination of rotate with flip, scaling or decimation is possible
* if buffer is unaligned.
*/
if(has_transform && (img_dsc->header.w % 16 || img_dsc->header.h % 16))
return false;
return true;
}
static int32_t _pxp_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
{
LV_UNUSED(u);
switch(t->type) {
case LV_DRAW_TASK_TYPE_FILL: {
const lv_draw_fill_dsc_t * draw_dsc = (lv_draw_fill_dsc_t *) t->draw_dsc;
/* Most simple case: just a plain rectangle (no radius, no gradient). */
if((draw_dsc->radius != 0) || (draw_dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))
return 0;
if(t->preference_score > 70) {
t->preference_score = 70;
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
}
return 1;
}
case LV_DRAW_TASK_TYPE_BG_IMG: {
const lv_draw_bg_image_dsc_t * draw_dsc = (lv_draw_bg_image_dsc_t *) t->draw_dsc;
lv_image_src_t src_type = lv_image_src_get_type(draw_dsc->src);
if(src_type == LV_IMAGE_SRC_SYMBOL)
return 0;
if(!_pxp_cf_supported(draw_dsc->img_header.cf))
return 0;
if(t->preference_score > 70) {
t->preference_score = 70;
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
}
return 1;
}
case LV_DRAW_TASK_TYPE_LAYER: {
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
lv_draw_buf_t * draw_buf = &layer_to_draw->draw_buf;
if(!_pxp_cf_supported(draw_buf->color_format))
return 0;
if(!_pxp_draw_img_supported(draw_dsc))
return 0;
if(t->preference_score > 70) {
t->preference_score = 70;
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
}
return 1;
}
case LV_DRAW_TASK_TYPE_IMAGE: {
lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
const lv_image_dsc_t * img_dsc = draw_dsc->src;
if(!_pxp_cf_supported(img_dsc->header.cf))
return 0;
if(!_pxp_draw_img_supported(draw_dsc))
return 0;
if(t->preference_score > 70) {
t->preference_score = 70;
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
}
return 1;
}
default:
return 0;
}
return 0;
}
static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
{
lv_draw_pxp_unit_t * draw_pxp_unit = (lv_draw_pxp_unit_t *) draw_unit;
/* Return immediately if it's busy with draw task. */
if(draw_pxp_unit->task_act)
return 0;
/* Return if target buffer format is not supported. */
if(!_pxp_cf_supported(layer->draw_buf.color_format))
return 0;
/* Try to get an ready to draw. */
lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_PXP);
/* Return 0 is no selection, some tasks can be supported only by other units. */
if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_PXP)
return 0;
void * buf = lv_draw_layer_alloc_buf(layer);
if(buf == NULL)
return -1;
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
draw_pxp_unit->base_unit.target_layer = layer;
draw_pxp_unit->base_unit.clip_area = &t->clip_area;
draw_pxp_unit->task_act = t;
#if LV_USE_OS
/* Let the render thread work. */
lv_thread_sync_signal(&draw_pxp_unit->sync);
#else
_pxp_execute_drawing(draw_pxp_unit);
draw_pxp_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
draw_pxp_unit->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
#endif
return 1;
}
static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u)
{
lv_draw_task_t * t = u->task_act;
lv_draw_unit_t * draw_unit = (lv_draw_unit_t *)u;
/* Invalidate cache */
lv_layer_t * layer = draw_unit->target_layer;
lv_draw_buf_invalidate_cache(&layer->draw_buf, (const char *)&t->area);
switch(t->type) {
case LV_DRAW_TASK_TYPE_FILL:
lv_draw_pxp_fill(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_BG_IMG:
lv_draw_pxp_bg_img(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_IMAGE:
lv_draw_pxp_img(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_LAYER:
lv_draw_pxp_layer(draw_unit, t->draw_dsc, &t->area);
break;
default:
break;
}
}
#if LV_USE_OS
static void _pxp_render_thread_cb(void * ptr)
{
lv_draw_pxp_unit_t * u = ptr;
lv_thread_sync_init(&u->sync);
while(1) {
/*
* Wait for sync if no task received or _draw_task_buf is empty.
* The thread will have to run as much as there are pending tasks.
*/
while(u->task_act == NULL) {
lv_thread_sync_wait(&u->sync);
}
_pxp_execute_drawing(u);
/* Cleanup. */
u->task_act->state = LV_DRAW_TASK_STATE_READY;
u->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
}
}
#endif
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,77 @@
/**
* @file lv_draw_pxp.h
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_DRAW_PXP_H
#define LV_DRAW_PXP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_PXP
#include "../../sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_layer_t lv_pxp_layer_t;
typedef struct {
lv_draw_unit_t base_unit;
struct _lv_draw_task_t * task_act;
#if LV_USE_OS
lv_thread_sync_t sync;
lv_thread_t thread;
#endif
} lv_draw_pxp_unit_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_buf_pxp_init_handlers(void);
void lv_draw_pxp_init(void);
void lv_draw_pxp_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_pxp_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_pxp_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_pxp_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_PXP*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_PXP_H*/

View File

@ -0,0 +1,94 @@
/**
* @file lv_draw_pxp_bg_img.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->src == NULL) return;
if(dsc->opa <= LV_OPA_MIN) return;
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
return;
}
const lv_area_t * clip_area_ori = draw_unit->clip_area;
draw_unit->clip_area = &clip_area;
lv_draw_image_dsc_t img_dsc;
lv_draw_image_dsc_init(&img_dsc);
img_dsc.recolor = dsc->recolor;
img_dsc.recolor_opa = dsc->recolor_opa;
img_dsc.opa = dsc->opa;
img_dsc.src = dsc->src;
/*Center align*/
if(dsc->tiled == false) {
lv_area_t area;
area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - dsc->img_header.w / 2;
area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - dsc->img_header.h / 2;
area.x2 = area.x1 + dsc->img_header.w - 1;
area.y2 = area.y1 + dsc->img_header.h - 1;
lv_draw_pxp_img(draw_unit, &img_dsc, &area);
}
else {
lv_area_t area;
area.y1 = coords->y1;
area.y2 = area.y1 + dsc->img_header.h - 1;
for(; area.y1 <= coords->y2; area.y1 += dsc->img_header.h, area.y2 += dsc->img_header.h) {
area.x1 = coords->x1;
area.x2 = area.x1 + dsc->img_header.w - 1;
for(; area.x1 <= coords->x2; area.x1 += dsc->img_header.w, area.x2 += dsc->img_header.w) {
lv_draw_pxp_img(draw_unit, &img_dsc, &area);
}
}
}
draw_unit->clip_area = clip_area_ori;
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,151 @@
/**
* @file lv_draw_pxp_fill.c
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_cfg.h"
#include "lv_pxp_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void _pxp_fill(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const lv_draw_fill_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
lv_layer_t * layer = draw_unit->target_layer;
lv_area_t rel_coords;
lv_area_copy(&rel_coords, coords);
lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t blend_area;
if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
return; /*Fully clipped, nothing to do*/
uint8_t * dest_buf = layer->draw_buf.buf;
lv_coord_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf);
lv_color_format_t dest_cf = layer->draw_buf.color_format;
_pxp_fill(dest_buf, &blend_area, dest_stride, dest_cf, dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _pxp_fill(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const lv_draw_fill_dsc_t * dsc)
{
lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_pxp_reset();
uint8_t px_size = lv_color_format_get_size(dest_cf);
/*OUT buffer configure*/
pxp_output_buffer_config_t outputConfig = {
.pixelFormat = pxp_get_out_px_format(dest_cf),
.interlacedMode = kPXP_OutputProgressive,
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + px_size * dest_area->x1),
.buffer1Addr = (uint32_t)NULL,
.pitchBytes = dest_stride,
.width = dest_w,
.height = dest_h
};
PXP_SetOutputBufferConfig(PXP_ID, &outputConfig);
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {
/*Simple color fill without opacity - AS disabled*/
PXP_SetAlphaSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
}
else {
/*Fill with opacity - AS used as source (same as OUT)*/
pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = pxp_get_as_px_format(dest_cf),
.bufferAddr = outputConfig.buffer0Addr,
.pitchBytes = outputConfig.pitchBytes
};
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
}
/*Disable PS, use as color generator*/
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to_u32(dsc->color));
/**
* Configure Porter-Duff blending - src settings are unused for fill without opacity (opa = 0xff).
*
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
* srcFactorMode is actually applied on PS alpha value
* dstFactorMode is actually applied on AS alpha value
*/
pxp_porter_duff_config_t pdConfig = {
.enable = 1,
.dstColorMode = kPXP_PorterDuffColorNoAlpha,
.srcColorMode = kPXP_PorterDuffColorNoAlpha,
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
.srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
.dstFactorMode = kPXP_PorterDuffFactorStraight,
.srcFactorMode = (dsc->opa >= (lv_opa_t)LV_OPA_MAX) ? kPXP_PorterDuffFactorStraight : kPXP_PorterDuffFactorInversed,
.dstGlobalAlpha = dsc->opa,
.srcGlobalAlpha = dsc->opa,
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
.srcAlphaMode = kPXP_PorterDuffAlphaStraight /*don't care*/
};
PXP_SetPorterDuffConfig(PXP_ID, &pdConfig);
lv_pxp_run();
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,364 @@
/**
* @file lv_draw_pxp_img.c
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_cfg.h"
#include "lv_pxp_utils.h"
#include <math.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/* Blit w/ recolor for images w/o opa and alpha channel */
static void _pxp_blit_recolor(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc);
/* Blit w/ transformation for images w/o opa and alpha channel */
static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc);
/* Blit simple w/ opa and alpha channel */
static void _pxp_blit(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, lv_opa_t opa);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
lv_layer_t * layer = draw_unit->target_layer;
const lv_image_dsc_t * img_dsc = dsc->src;
lv_area_t rel_coords;
lv_area_copy(&rel_coords, coords);
lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t blend_area;
bool has_transform = dsc->rotation != 0 || dsc->zoom != LV_SCALE_NONE;
if(has_transform)
lv_area_copy(&blend_area, &rel_coords);
else if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
return; /*Fully clipped, nothing to do*/
const uint8_t * src_buf = img_dsc->data;
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (coords->x1 - layer->draw_buf_ofs.x);
src_area.y1 = blend_area.y1 - (coords->y1 - layer->draw_buf_ofs.y);
src_area.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 = img_dsc->header.stride;
lv_color_format_t src_cf = img_dsc->header.cf;
uint8_t * dest_buf = layer->draw_buf.buf;
lv_coord_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf);
lv_color_format_t dest_cf = layer->draw_buf.color_format;
bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
if(has_recolor && !has_transform)
_pxp_blit_recolor(dest_buf, &blend_area, dest_stride, dest_cf,
src_buf, &src_area, src_stride, src_cf, dsc);
else if(has_transform)
_pxp_blit_transform(dest_buf, &blend_area, dest_stride, dest_cf,
src_buf, &src_area, src_stride, src_cf, dsc);
else
_pxp_blit(dest_buf, &blend_area, dest_stride, dest_cf,
src_buf, &src_area, src_stride, src_cf, dsc->opa);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _pxp_blit_recolor(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc)
{
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 src_has_alpha = (src_cf == LV_COLOR_FORMAT_ARGB8888);
uint8_t src_px_size = lv_color_format_get_size(src_cf);
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
lv_pxp_reset();
/*AS buffer - source image*/
pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = pxp_get_as_px_format(src_cf),
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
.pitchBytes = src_stride
};
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
/*Disable PS, use as color generator*/
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to_u32(dsc->recolor));
/*Output buffer*/
pxp_output_buffer_config_t outputBufferConfig = {
.pixelFormat = pxp_get_out_px_format(dest_cf),
.interlacedMode = kPXP_OutputProgressive,
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
.buffer1Addr = (uint32_t)0U,
.pitchBytes = dest_stride,
.width = dest_w,
.height = dest_h
};
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
/**
* Configure Porter-Duff blending.
*
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
* srcFactorMode is actually applied on PS alpha value
* dstFactorMode is actually applied on AS alpha value
*/
pxp_porter_duff_config_t pdConfig = {
.enable = 1,
.dstColorMode = kPXP_PorterDuffColorWithAlpha,
.srcColorMode = kPXP_PorterDuffColorWithAlpha,
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
.srcGlobalAlphaMode = src_has_alpha ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha,
.dstFactorMode = kPXP_PorterDuffFactorStraight,
.srcFactorMode = kPXP_PorterDuffFactorInversed,
.dstGlobalAlpha = dsc->recolor_opa,
.srcGlobalAlpha = 0xff,
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
.srcAlphaMode = kPXP_PorterDuffAlphaStraight
};
PXP_SetPorterDuffConfig(PXP_ID, &pdConfig);
lv_pxp_run();
}
static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc)
{
lv_coord_t src_w = lv_area_get_width(src_area);
lv_coord_t src_h = lv_area_get_height(src_area);
lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_point_t pivot = dsc->pivot;
/*The offsets are now relative to the transformation result with pivot ULC*/
lv_coord_t piv_offset_x = 0;
lv_coord_t piv_offset_y = 0;
lv_coord_t trim_size = 0;
bool has_rotation = (dsc->rotation != 0);
bool has_scale = (dsc->zoom != LV_SCALE_NONE);
uint8_t src_px_size = lv_color_format_get_size(src_cf);
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
lv_pxp_reset();
if(has_rotation) {
/*Convert rotation angle and calculate offsets caused by pivot*/
pxp_rotate_degree_t pxp_angle;
switch(dsc->rotation) {
case 0:
pxp_angle = kPXP_Rotate0;
piv_offset_x = 0;
piv_offset_y = 0;
break;
case 900:
pxp_angle = kPXP_Rotate90;
piv_offset_x = pivot.x + pivot.y - src_h;
piv_offset_y = pivot.y - pivot.x;
break;
case 1800:
pxp_angle = kPXP_Rotate180;
piv_offset_x = 2 * pivot.x - src_w;
piv_offset_y = 2 * pivot.y - src_h;
break;
case 2700:
pxp_angle = kPXP_Rotate270;
piv_offset_x = pivot.x - pivot.y;
piv_offset_y = pivot.x + pivot.y - src_w;
break;
default:
pxp_angle = kPXP_Rotate0;
piv_offset_x = 0;
piv_offset_y = 0;
}
/*PS buffer rotation and decimation does not function at the same time*/
PXP_SetRotateConfig(PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable);
}
if(has_scale) {
float scale_factor_fp = (float)dsc->zoom / LV_SCALE_NONE;
lv_coord_t scale_factor_int = (lv_coord_t)scale_factor_fp;
/*Any scale_factor in (k, k + 1] will result in a trim equal to k*/
if(scale_factor_fp == scale_factor_int)
trim_size = scale_factor_int - 1;
else
trim_size = scale_factor_int;
dest_w = src_w * scale_factor_fp + trim_size;
dest_h = src_h * scale_factor_fp + trim_size;
/*Final pivot offset = scale_factor * rotation_pivot_offset + scaling_pivot_offset*/
piv_offset_x = floor(scale_factor_fp * piv_offset_x) - floor((scale_factor_fp - 1) * pivot.x);
piv_offset_y = floor(scale_factor_fp * piv_offset_y) - floor((scale_factor_fp - 1) * pivot.y);
}
/*PS buffer - source image*/
pxp_ps_buffer_config_t psBufferConfig = {
.pixelFormat = pxp_get_ps_px_format(src_cf),
.swapByte = false,
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
.bufferAddrU = 0,
.bufferAddrV = 0,
.pitchBytes = src_stride
};
PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig);
PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - trim_size - 1U, dest_h - trim_size - 1U);
if(has_scale)
PXP_SetProcessSurfaceScaler(PXP_ID, src_w, src_h, dest_w, dest_h);
/*AS disabled */
PXP_SetAlphaSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
/*Output buffer*/
pxp_output_buffer_config_t outputBufferConfig = {
.pixelFormat = pxp_get_out_px_format(dest_cf),
.interlacedMode = kPXP_OutputProgressive,
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * (dest_area->y1 + piv_offset_y) + dest_px_size * (dest_area->x1 + piv_offset_x)),
.buffer1Addr = (uint32_t)0U,
.pitchBytes = dest_stride,
.width = dest_w - trim_size,
.height = dest_h - trim_size
};
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
lv_pxp_run();
}
static void _pxp_blit(uint8_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
lv_coord_t src_stride, lv_color_format_t src_cf, lv_opa_t opa)
{
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 src_has_alpha = (src_cf == LV_COLOR_FORMAT_ARGB8888);
uint8_t src_px_size = lv_color_format_get_size(src_cf);
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
lv_pxp_reset();
pxp_as_blend_config_t asBlendConfig = {
.alpha = opa,
.invertAlpha = false,
.alphaMode = kPXP_AlphaRop,
.ropMode = kPXP_RopMergeAs
};
if(opa >= (lv_opa_t)LV_OPA_MAX && !src_has_alpha) {
/*Simple blit, no effect - Disable PS buffer*/
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
}
else {
/*PS must be enabled to fetch background pixels.
PS and OUT buffers are the same, blend will be done in-place*/
pxp_ps_buffer_config_t psBufferConfig = {
.pixelFormat = pxp_get_ps_px_format(dest_cf),
.swapByte = false,
.bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
.bufferAddrU = 0U,
.bufferAddrV = 0U,
.pitchBytes = dest_stride
};
if(opa >= (lv_opa_t)LV_OPA_MAX)
asBlendConfig.alphaMode = src_has_alpha ? kPXP_AlphaEmbedded : kPXP_AlphaOverride;
else
asBlendConfig.alphaMode = src_has_alpha ? kPXP_AlphaMultiply : kPXP_AlphaOverride;
PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig);
PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
}
/*AS buffer - source image*/
pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = pxp_get_as_px_format(src_cf),
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
.pitchBytes = src_stride
};
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
PXP_SetAlphaSurfaceBlendConfig(PXP_ID, &asBlendConfig);
PXP_EnableAlphaSurfaceOverlayColorKey(PXP_ID, false);
/*Output buffer.*/
pxp_output_buffer_config_t outputBufferConfig = {
.pixelFormat = pxp_get_out_px_format(dest_cf),
.interlacedMode = kPXP_OutputProgressive,
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
.buffer1Addr = (uint32_t)0U,
.pitchBytes = dest_stride,
.width = dest_w,
.height = dest_h
};
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
lv_pxp_run();
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,71 @@
/**
* @file lv_draw_pxp_layer.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_DRAW_PXP
#include "../../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords)
{
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
/*It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
*In this case just return. */
if(layer_to_draw->draw_buf.buf == NULL)
return;
lv_image_dsc_t img_dsc;
img_dsc.header.w = layer_to_draw->draw_buf.width;
img_dsc.header.h = layer_to_draw->draw_buf.height;
img_dsc.header.cf = layer_to_draw->draw_buf.color_format;
img_dsc.header.always_zero = 0;
img_dsc.data = lv_draw_buf_get_buf(&layer_to_draw->draw_buf);
lv_draw_image_dsc_t new_draw_dsc;
lv_memcpy(&new_draw_dsc, draw_dsc, sizeof(lv_draw_image_dsc_t));
new_draw_dsc.src = &img_dsc;
lv_draw_pxp_img(draw_unit, &new_draw_dsc, coords);
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,96 @@
/**
* @file lv_pxp_cfg.c
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_pxp_cfg.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_osa.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static pxp_cfg_t * _pxp_cfg;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_pxp_init(void)
{
_pxp_cfg = pxp_get_default_cfg();
if(!_pxp_cfg || !_pxp_cfg->pxp_interrupt_deinit || !_pxp_cfg->pxp_interrupt_init ||
!_pxp_cfg->pxp_run || !_pxp_cfg->pxp_wait)
LV_LOG_ERROR("PXP configuration error.");
PXP_Init(PXP_ID);
PXP_EnableCsc1(PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
PXP_EnableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
_pxp_cfg->pxp_interrupt_init();
}
void lv_pxp_deinit(void)
{
_pxp_cfg->pxp_interrupt_deinit();
PXP_DisableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
PXP_Deinit(PXP_ID);
}
void lv_pxp_reset(void)
{
PXP_ResetControl(PXP_ID);
PXP_EnableCsc1(PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
}
void lv_pxp_run(void)
{
_pxp_cfg->pxp_run();
_pxp_cfg->pxp_wait();
}
void lv_pxp_wait(void)
{
_pxp_cfg->pxp_wait();
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,103 @@
/**
* @file lv_pxp_cfg.h
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_PXP_CFG_H
#define LV_PXP_CFG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_PXP
#include "fsl_cache.h"
#include "fsl_pxp.h"
#include "../../../misc/lv_log.h"
/*********************
* DEFINES
*********************/
/** PXP module instance to use*/
#define PXP_ID PXP
/** PXP interrupt line ID*/
#define PXP_IRQ_ID PXP_IRQn
/**********************
* TYPEDEFS
**********************/
/**
* NXP PXP device configuration.
*/
typedef struct {
/** Callback for PXP interrupt initialization*/
void (*pxp_interrupt_init)(void);
/** Callback for PXP interrupt de-initialization*/
void (*pxp_interrupt_deinit)(void);
/** Callback for PXP start*/
void (*pxp_run)(void);
/** Callback for waiting of PXP completion*/
void (*pxp_wait)(void);
} pxp_cfg_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Reset and initialize PXP device. This function should be called as a part
* of display init sequence.
*/
void lv_pxp_init(void);
/**
* Disable PXP device. Should be called during display deinit sequence.
*/
void lv_pxp_deinit(void);
/**
* Reset PXP device.
*/
void lv_pxp_reset(void);
/**
* Clear cache and start PXP.
*/
void lv_pxp_run(void);
/**
* Wait for PXP completion.
*/
void lv_pxp_wait(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_PXP*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_PXP_CFG_H*/

View File

@ -0,0 +1,168 @@
/**
* @file lv_pxp_osa.c
*
*/
/**
* Copyright 2020, 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_pxp_osa.h"
#if LV_USE_DRAW_PXP
#include "../../../misc/lv_log.h"
#include "fsl_pxp.h"
#if defined(SDK_OS_FREE_RTOS)
#include "FreeRTOS.h"
#include "semphr.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* PXP interrupt initialization.
*/
static void _pxp_interrupt_init(void);
/**
* PXP interrupt de-initialization.
*/
static void _pxp_interrupt_deinit(void);
/**
* Start the PXP job.
*/
static void _pxp_run(void);
/**
* Wait for PXP completion.
*/
static void _pxp_wait(void);
/**********************
* STATIC VARIABLES
**********************/
#if defined(SDK_OS_FREE_RTOS)
static SemaphoreHandle_t xPXPIdleSemaphore;
#endif
static volatile bool ucPXPIdle;
static pxp_cfg_t _pxp_default_cfg = {
.pxp_interrupt_init = _pxp_interrupt_init,
.pxp_interrupt_deinit = _pxp_interrupt_deinit,
.pxp_run = _pxp_run,
.pxp_wait = _pxp_wait,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void PXP_IRQHandler(void)
{
#if defined(SDK_OS_FREE_RTOS)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#endif
if(kPXP_CompleteFlag & PXP_GetStatusFlags(PXP_ID)) {
PXP_ClearStatusFlags(PXP_ID, kPXP_CompleteFlag);
#if defined(SDK_OS_FREE_RTOS)
xSemaphoreGiveFromISR(xPXPIdleSemaphore, &xHigherPriorityTaskWoken);
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
should be performed to ensure the interrupt returns directly to the highest
priority task. The macro used for this purpose is dependent on the port in
use and may be called portEND_SWITCHING_ISR(). */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#else
ucPXPIdle = true;
#endif
}
}
pxp_cfg_t * pxp_get_default_cfg(void)
{
return &_pxp_default_cfg;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _pxp_interrupt_init(void)
{
#if defined(SDK_OS_FREE_RTOS)
xPXPIdleSemaphore = xSemaphoreCreateBinary();
if(xPXPIdleSemaphore == NULL) {
LV_LOG_ERROR("xSemaphoreCreateBinary failed!");
return;
}
NVIC_SetPriority(PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
#endif
ucPXPIdle = true;
NVIC_EnableIRQ(PXP_IRQ_ID);
}
static void _pxp_interrupt_deinit(void)
{
NVIC_DisableIRQ(PXP_IRQ_ID);
#if defined(SDK_OS_FREE_RTOS)
vSemaphoreDelete(xPXPIdleSemaphore);
#endif
}
/**
* Function to start PXP job.
*/
static void _pxp_run(void)
{
ucPXPIdle = false;
PXP_EnableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
PXP_Start(PXP_ID);
}
/**
* Function to wait for PXP completion.
*/
static void _pxp_wait(void)
{
#if defined(SDK_OS_FREE_RTOS)
/* Return if PXP was never started, otherwise the semaphore will lock forever. */
if(ucPXPIdle == true)
return;
if(xSemaphoreTake(xPXPIdleSemaphore, portMAX_DELAY) == pdTRUE)
ucPXPIdle = true;
#else
while(ucPXPIdle == false) {
}
#endif
}
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,61 @@
/**
* @file lv_pxp_osa.h
*
*/
/**
* Copyright 2020, 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_PXP_OSA_H
#define LV_PXP_OSA_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_PXP
#include "lv_pxp_cfg.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* PXP device interrupt handler. Used to check PXP task completion status.
*/
void PXP_IRQHandler(void);
/**
* Get the PXP default configuration.
*/
pxp_cfg_t * pxp_get_default_cfg(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_PXP*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_PXP_OSA_H*/

View File

@ -0,0 +1,151 @@
/**
* @file lv_pxp_utils.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_pxp_utils.h"
#if LV_USE_DRAW_PXP
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf)
{
pxp_output_pixel_format_t out_px_format = kPXP_OutputPixelFormatRGB565;
switch(cf) {
/*2 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB565:
out_px_format = kPXP_OutputPixelFormatRGB565;
break;
case LV_COLOR_FORMAT_RGB565A8:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
/*3 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB888:
out_px_format = kPXP_OutputPixelFormatRGB888P;
break;
case LV_COLOR_FORMAT_ARGB8888:
out_px_format = kPXP_OutputPixelFormatARGB8888;
break;
case LV_COLOR_FORMAT_XRGB8888:
out_px_format = kPXP_OutputPixelFormatRGB888;
break;
default:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
}
return out_px_format;
}
pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf)
{
pxp_as_pixel_format_t as_px_format = kPXP_AsPixelFormatRGB565;
switch(cf) {
/*2 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB565:
as_px_format = kPXP_AsPixelFormatRGB565;
break;
case LV_COLOR_FORMAT_RGB565A8:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
/*3 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB888:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
case LV_COLOR_FORMAT_ARGB8888:
as_px_format = kPXP_AsPixelFormatARGB8888;
break;
case LV_COLOR_FORMAT_XRGB8888:
as_px_format = kPXP_AsPixelFormatRGB888;
break;
default:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
}
return as_px_format;
}
pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf)
{
pxp_ps_pixel_format_t ps_px_format = kPXP_PsPixelFormatRGB565;
switch(cf) {
/*2 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB565:
ps_px_format = kPXP_PsPixelFormatRGB565;
break;
case LV_COLOR_FORMAT_RGB565A8:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
/*3 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB888:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
case LV_COLOR_FORMAT_ARGB8888:
#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
(!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
ps_px_format = kPXP_PsPixelFormatARGB8888;
#else
LV_ASSERT_MSG(false, "Unsupported color format.");
#endif
break;
case LV_COLOR_FORMAT_XRGB8888:
#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
(!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
ps_px_format = kPXP_PsPixelFormatARGB8888;
#else
ps_px_format = kPXP_PsPixelFormatRGB888;
#endif
break;
default:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
}
return ps_px_format;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_PXP*/

View File

@ -0,0 +1,65 @@
/**
* @file lv_pxp_utils.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_PXP_UTILS_H
#define LV_PXP_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_PXP
#include "fsl_pxp.h"
#include "../../../misc/lv_color.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf);
pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf);
pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf);
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_PXP*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_PXP_UTILS_H*/

View File

@ -0,0 +1,194 @@
/**
* @file lv_draw_buf_vglite.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_matrix.h"
#include "lv_vglite_utils.h"
#include "lvgl_support.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void * _buf_malloc(size_t size_bytes, lv_color_format_t cf);
static void * _align_buf(void * buf, lv_color_format_t cf);
static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area);
static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf);
static void * _go_to_xy(lv_draw_buf_t * draw_buf, lv_coord_t x, lv_coord_t y);
static void _vglite_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * area);
static void _vglite_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area,
void * src_buf, uint32_t src_stride, const lv_area_t * src_area, lv_color_format_t cf);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_buf_vglite_init_handlers(void)
{
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
handlers->buf_malloc_cb = _buf_malloc;
handlers->align_pointer_cb = _align_buf;
handlers->invalidate_cache_cb = _invalidate_cache;
handlers->width_to_stride_cb = _width_to_stride;
handlers->go_to_xy_cb = _go_to_xy;
handlers->buf_clear_cb = _vglite_buf_clear;
handlers->buf_copy_cb = _vglite_buf_copy;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void * _buf_malloc(size_t size_bytes, lv_color_format_t cf)
{
uint8_t align_bytes = vglite_get_alignment(cf);
/*Allocate larger memory to be sure it can be aligned as needed*/
size_bytes += align_bytes - 1;
return lv_malloc(size_bytes);
}
static void * _align_buf(void * buf, lv_color_format_t cf)
{
uint8_t align_bytes = vglite_get_alignment(cf);
uint8_t * buf_u8 = buf;
if(buf_u8) {
buf_u8 += align_bytes - 1;
buf_u8 = (uint8_t *)((lv_uintptr_t)buf_u8 & ~(align_bytes - 1));
}
return buf_u8;
}
static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area)
{
LV_UNUSED(draw_buf);
LV_UNUSED(area);
DEMO_CleanInvalidateCache();
}
static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf)
{
uint8_t bits_per_pixel = vglite_get_px_size(cf);
uint32_t width_bits = (w * bits_per_pixel + 7) & ~7;
uint32_t width_bytes = width_bits / 8;
uint8_t align_bytes = vglite_get_alignment(cf);
return (width_bytes + align_bytes - 1) & ~(align_bytes - 1);
}
static void * _go_to_xy(lv_draw_buf_t * draw_buf, lv_coord_t x, lv_coord_t y)
{
uint8_t bits_per_pixel = vglite_get_px_size(draw_buf->color_format);
uint32_t stride = lv_draw_buf_get_stride(draw_buf);
uint8_t * buf_tmp = lv_draw_buf_get_buf(draw_buf);
buf_tmp += stride * y;
buf_tmp += (x * bits_per_pixel) / 8;
return buf_tmp;
}
static void _vglite_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * area)
{
uint32_t stride = lv_draw_buf_get_stride(draw_buf);
/* Set vgbuf structure. */
vg_lite_buffer_t vgbuf;
vglite_set_buf(&vgbuf, draw_buf->buf, draw_buf->width, draw_buf->height, stride, draw_buf->color_format);
vg_lite_color_t vgcol = 0;
vg_lite_rectangle_t rect = {
.x = area->x1,
.y = area->y1,
.width = lv_area_get_width(area),
.height = lv_area_get_height(area)
};
vg_lite_error_t err = vg_lite_clear(&vgbuf, &rect, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear failed.");
vglite_run();
}
static void _vglite_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area,
void * src_buf, uint32_t src_stride, const lv_area_t * src_area,
lv_color_format_t cf)
{
/* Set src_vgbuf structure. */
vg_lite_buffer_t src_vgbuf;
vglite_set_buf(&src_vgbuf, src_buf, lv_area_get_width(src_area), lv_area_get_height(src_area), src_stride, cf);
/* Set dest_vgbuf structure. */
vg_lite_buffer_t dest_vgbuf;
vglite_set_buf(&dest_vgbuf, dest_buf, lv_area_get_width(dest_area), lv_area_get_height(dest_area), dest_stride, cf);
uint32_t rect[] = {
(uint32_t)src_area->x1, /* start x */
(uint32_t)src_area->y1, /* start y */
(uint32_t)lv_area_get_width(src_area), /* width */
(uint32_t)lv_area_get_height(src_area) /* height */
};
/* Set scissor. */
vglite_set_scissor(dest_area);
/* Set vgmatrix. */
vglite_set_translation_matrix(dest_area);
vg_lite_matrix_t * vgmatrix = vglite_get_matrix();
vg_lite_error_t err = vg_lite_blit_rect(&dest_vgbuf, &src_vgbuf, rect, vgmatrix,
VG_LITE_BLEND_NONE, 0xFFFFFFFFU, VG_LITE_FILTER_POINT);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Blit rectangle failed.");
vglite_run();
/* Disable scissor. */
vglite_disable_scissor();
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,439 @@
/**
* @file lv_draw_vglite.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_utils.h"
#include "../../../display/lv_display_private.h"
/*********************
* DEFINES
*********************/
#define DRAW_UNIT_ID_VGLITE 2
#if LV_USE_OS
#define VGLITE_TASK_BUF_SIZE 10
#endif
/**********************
* TYPEDEFS
**********************/
#if LV_USE_OS
/**
* Structure of pending vglite draw task
*/
typedef struct _vglite_draw_task_t {
lv_draw_task_t * task;
bool flushed;
} vglite_draw_tasks_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
/*
* Dispatch a task to the VGLite unit.
* Return 1 if task was dispatched, 0 otherwise (task not supported).
*/
static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
/*
* Evaluate a task and set the score and preferred VGLite unit.
* Return 1 if task is preferred, 0 otherwise (task is not supported).
*/
static int32_t _vglite_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
#if LV_USE_OS
static void _vglite_render_thread_cb(void * ptr);
#endif
static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u);
/**********************
* STATIC VARIABLES
**********************/
#if LV_USE_OS
/*
* Circular buffer to hold the queued and the flushed tasks.
* Two indexes, _head and _tail, are used to signal the beginning
* and the end of the valid tasks that are pending.
*/
static vglite_draw_tasks_t _draw_task_buf[VGLITE_TASK_BUF_SIZE];
static volatile int _head = 0;
static volatile int _tail = 0;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_init(void)
{
lv_draw_buf_vglite_init_handlers();
lv_draw_vglite_unit_t * draw_vglite_unit = lv_draw_create_unit(sizeof(lv_draw_vglite_unit_t));
draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch;
draw_vglite_unit->base_unit.evaluate_cb = _vglite_evaluate;
#if LV_USE_OS
lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 8 * 1024, draw_vglite_unit);
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
static inline bool _vglite_cf_supported(lv_color_format_t cf)
{
// Add here the platform specific code for supported formats.
bool is_cf_unsupported = (cf == LV_COLOR_FORMAT_RGB565A8 || cf == LV_COLOR_FORMAT_RGB888);
return (!is_cf_unsupported);
}
static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
{
LV_UNUSED(u);
switch(t->type) {
case LV_DRAW_TASK_TYPE_FILL:
if(t->preference_score > 80) {
t->preference_score = 80;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
case LV_DRAW_TASK_TYPE_LINE:
case LV_DRAW_TASK_TYPE_ARC:
if(t->preference_score > 90) {
t->preference_score = 90;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
case LV_DRAW_TASK_TYPE_LABEL:
if(t->preference_score > 95) {
t->preference_score = 95;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
case LV_DRAW_TASK_TYPE_BORDER: {
const lv_draw_border_dsc_t * draw_dsc = (lv_draw_border_dsc_t *) t->draw_dsc;
if(draw_dsc->side != (lv_border_side_t)LV_BORDER_SIDE_FULL)
return 0;
if(t->preference_score > 90) {
t->preference_score = 90;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
}
case LV_DRAW_TASK_TYPE_BG_IMG: {
const lv_draw_bg_image_dsc_t * draw_dsc = (lv_draw_bg_image_dsc_t *) t->draw_dsc;
lv_image_src_t src_type = lv_image_src_get_type(draw_dsc->src);
if(src_type != LV_IMAGE_SRC_SYMBOL) {
bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP);
if(has_recolor
|| (!_vglite_cf_supported(draw_dsc->img_header.cf))
|| (!vglite_buf_aligned(draw_dsc->src, draw_dsc->img_header.stride, draw_dsc->img_header.cf))
)
return 0;
}
if(t->preference_score > 80) {
t->preference_score = 80;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
}
case LV_DRAW_TASK_TYPE_LAYER: {
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
lv_draw_buf_t * draw_buf = &layer_to_draw->draw_buf;
bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP);
if(has_recolor
|| (!_vglite_cf_supported(draw_buf->color_format))
)
return 0;
if(t->preference_score > 80) {
t->preference_score = 80;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
}
case LV_DRAW_TASK_TYPE_IMAGE: {
lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
const lv_image_dsc_t * img_dsc = draw_dsc->src;
bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP);
#if VGLITE_BLIT_SPLIT_ENABLED
bool has_transform = (draw_dsc->angle != 0 || draw_dsc->zoom != LV_ZOOM_NONE);
#endif
if(has_recolor
#if VGLITE_BLIT_SPLIT_ENABLED
|| has_transform
#endif
|| (!_vglite_cf_supported(img_dsc->header.cf))
|| (!vglite_buf_aligned(img_dsc->data, img_dsc->header.stride, img_dsc->header.cf))
)
return 0;
if(t->preference_score > 80) {
t->preference_score = 80;
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
}
return 1;
}
default:
return 0;
}
return 0;
}
static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
{
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
/* Return immediately if it's busy with draw task. */
if(draw_vglite_unit->task_act)
return 0;
/* Return if target buffer format is not supported.
*
* FIXME: Source format and destination format support is different!
*/
if(!_vglite_cf_supported(layer->draw_buf.color_format))
return 0;
/* Try to get an ready to draw. */
lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_VGLITE);
/* Return 0 is no selection, some tasks can be supported by other units. */
if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_VGLITE)
return 0;
void * buf = lv_draw_layer_alloc_buf(layer);
if(buf == NULL)
return -1;
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
draw_vglite_unit->base_unit.target_layer = layer;
draw_vglite_unit->base_unit.clip_area = &t->clip_area;
draw_vglite_unit->task_act = t;
#if LV_USE_OS
/* Let the render thread work. */
lv_thread_sync_signal(&draw_vglite_unit->sync);
#else
_vglite_execute_drawing(draw_vglite_unit);
draw_vglite_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
draw_vglite_unit->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
#endif
return 1;
}
static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u)
{
lv_draw_task_t * t = u->task_act;
lv_draw_unit_t * draw_unit = (lv_draw_unit_t *)u;
/* Set target buffer */
lv_layer_t * layer = draw_unit->target_layer;
vglite_set_dest_buf(&layer->draw_buf);
/* Invalidate cache */
lv_draw_buf_invalidate_cache(&layer->draw_buf, (const char *)&t->area);
switch(t->type) {
case LV_DRAW_TASK_TYPE_LABEL:
lv_draw_vglite_label(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_FILL:
lv_draw_vglite_fill(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_BORDER:
lv_draw_vglite_border(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_BG_IMG:
lv_draw_vglite_bg_img(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_IMAGE:
lv_draw_vglite_img(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_ARC:
lv_draw_vglite_arc(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_LINE:
lv_draw_vglite_line(draw_unit, t->draw_dsc);
break;
case LV_DRAW_TASK_TYPE_LAYER:
lv_draw_vglite_layer(draw_unit, t->draw_dsc, &t->area);
break;
default:
break;
}
#if LV_USE_PARALLEL_DRAW_DEBUG
/* Layers manage it for themselves. */
if(t->type != LV_DRAW_TASK_TYPE_LAYER) {
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &t->area, u->base_unit.clip_area))
return;
int32_t idx = 0;
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
lv_draw_unit_t * draw_unit_tmp = disp->draw_unit_head;
while(draw_unit_tmp != (lv_draw_unit_t *)u) {
draw_unit_tmp = draw_unit_tmp->next;
idx++;
}
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.bg_color = lv_palette_main(idx % _LV_PALETTE_LAST);
rect_dsc.border_color = rect_dsc.bg_color;
rect_dsc.bg_opa = LV_OPA_10;
rect_dsc.border_opa = LV_OPA_80;
rect_dsc.border_width = 1;
lv_draw_vglite_rect((lv_draw_unit_t *)u, &rect_dsc, &draw_area);
lv_point_t txt_size;
lv_txt_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
lv_area_t txt_area;
txt_area.x1 = draw_area.x1;
txt_area.y1 = draw_area.y1;
txt_area.x2 = draw_area.x1 + txt_size.x - 1;
txt_area.y2 = draw_area.y1 + txt_size.y - 1;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.bg_color = lv_color_white();
lv_draw_vglite_rect((lv_draw_unit_t *)u, &rect_dsc, &txt_area);
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d", idx);
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.color = lv_color_black();
label_dsc.text = buf;
lv_draw_vglite_label((lv_draw_unit_t *)u, &label_dsc, &txt_area);
}
#endif
}
#if LV_USE_OS
static inline void _vglite_queue_task(lv_draw_task_t * task_act)
{
_draw_task_buf[_tail].task = task_act;
_draw_task_buf[_tail].flushed = false;
_tail = (_tail + 1) % VGLITE_TASK_BUF_SIZE;
}
static inline void _vglite_signal_task_ready(lv_draw_task_t * task_act)
{
if(vglite_cmd_buf_is_flushed()) {
int end = (_head < _tail) ? _tail : _tail + VGLITE_TASK_BUF_SIZE;
for(int i = _head; i < end; i++) {
/* Previous flushed tasks are ready now. */
if(_draw_task_buf[i % VGLITE_TASK_BUF_SIZE].flushed) {
lv_draw_task_t * task = _draw_task_buf[i % VGLITE_TASK_BUF_SIZE].task;
/* Signal the ready state to dispatcher. */
task->state = LV_DRAW_TASK_STATE_READY;
_head = (_head + 1) % VGLITE_TASK_BUF_SIZE;
/* No need to cleanup the tasks in buffer as we advance with the _head. */
}
else {
/* Those tasks have been flushed now. */
_draw_task_buf[i % VGLITE_TASK_BUF_SIZE].flushed = true;
}
}
}
if(task_act)
LV_ASSERT_MSG(_tail != _head, "VGLite task buffer full.");
}
static void _vglite_render_thread_cb(void * ptr)
{
lv_draw_vglite_unit_t * u = ptr;
lv_thread_sync_init(&u->sync);
while(1) {
/*
* Wait for sync if no task received or _draw_task_buf is empty.
* The thread will have to run as much as there are pending tasks.
*/
while(u->task_act == NULL && _head == _tail) {
lv_thread_sync_wait(&u->sync);
}
if(u->task_act) {
_vglite_queue_task((void *)u->task_act);
_vglite_execute_drawing(u);
}
else {
/*
* Update the flush status for last pending tasks.
* vg_lite_flush() will early return if there is nothing to submit.
*/
vglite_run();
}
_vglite_signal_task_ready((void *)u->task_act);
/* Cleanup. */
u->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
}
}
#endif
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,101 @@
/**
* @file lv_draw_vglite.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_DRAW_VGLITE_H
#define LV_DRAW_VGLITE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_VGLITE
#include "../../sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/**
* Enable BLIT quality degradation workaround for RT595,
* recommended for screen's dimension > 352 pixels.
*/
#define RT595_BLIT_WRKRND_ENABLED 1
/* Internal compound symbol */
#if (defined(CPU_MIMXRT595SFFOB) || defined(CPU_MIMXRT595SFFOB_cm33) || \
defined(CPU_MIMXRT595SFFOC) || defined(CPU_MIMXRT595SFFOC_cm33)) && \
RT595_BLIT_WRKRND_ENABLED
#define VGLITE_BLIT_SPLIT_ENABLED 1
#else
#define VGLITE_BLIT_SPLIT_ENABLED 0
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_draw_unit_t base_unit;
struct _lv_draw_task_t * task_act;
#if LV_USE_OS
lv_thread_sync_t sync;
lv_thread_t thread;
#endif
} lv_draw_vglite_unit_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_buf_vglite_init_handlers(void);
void lv_draw_vglite_init(void);
void lv_draw_vglite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vglite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
void lv_draw_vglite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_VGLITE_H*/

View File

@ -0,0 +1,691 @@
/**
* @file lv_draw_vglite_arc.c
*
*/
/**
* Copyright 2021-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_path.h"
#include "lv_vglite_utils.h"
#include "../../../stdlib/lv_string.h"
#include <math.h>
/*********************
* DEFINES
*********************/
#define T_FRACTION 16384.0f
#define DICHOTO_ITER 5
static const uint16_t TperDegree[90] = {
0, 174, 348, 522, 697, 873, 1049, 1226, 1403, 1581,
1759, 1938, 2117, 2297, 2477, 2658, 2839, 3020, 3202, 3384,
3567, 3749, 3933, 4116, 4300, 4484, 4668, 4852, 5037, 5222,
5407, 5592, 5777, 5962, 6148, 6334, 6519, 6705, 6891, 7077,
7264, 7450, 7636, 7822, 8008, 8193, 8378, 8564, 8750, 8936,
9122, 9309, 9495, 9681, 9867, 10052, 10238, 10424, 10609, 10794,
10979, 11164, 11349, 11534, 11718, 11902, 12086, 12270, 12453, 12637,
12819, 13002, 13184, 13366, 13547, 13728, 13909, 14089, 14269, 14448,
14627, 14805, 14983, 15160, 15337, 15513, 15689, 15864, 16038, 16212
};
/**********************
* TYPEDEFS
**********************/
/* intermediate arc params */
typedef struct _vg_arc {
int32_t angle; /* angle <90deg */
int32_t quarter; /* 0-3 counter-clockwise */
int32_t rad; /* radius */
int32_t p0x; /* point P0 */
int32_t p0y;
int32_t p1x; /* point P1 */
int32_t p1y;
int32_t p2x; /* point P2 */
int32_t p2y;
int32_t p3x; /* point P3 */
int32_t p3y;
} vg_arc;
typedef struct _cubic_cont_pt {
float p0;
float p1;
float p2;
float p3;
} cubic_cont_pt;
/**********************
* STATIC PROTOTYPES
**********************/
/**
* Draw arc shape with effects
*
* @param[in] center Arc center with relative coordinates
* @param[in] clip_area Clipping area with relative coordinates to dest buff
* @param[in] dsc Arc description structure (width, rounded ending, opacity)
*
*/
static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_area,
const lv_draw_arc_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
const lv_area_t * coords)
{
LV_UNUSED(coords);
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
if(dsc->start_angle == dsc->end_angle)
return;
lv_layer_t * layer = draw_unit->target_layer;
lv_point_t rel_center = {dsc->center.x - layer->draw_buf_ofs.x, dsc->center.y - layer->draw_buf_ofs.y};
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
_vglite_draw_arc(&rel_center, &rel_clip_area, dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _copy_arc(vg_arc * dst, vg_arc * src)
{
dst->quarter = src->quarter;
dst->rad = src->rad;
dst->angle = src->angle;
dst->p0x = src->p0x;
dst->p1x = src->p1x;
dst->p2x = src->p2x;
dst->p3x = src->p3x;
dst->p0y = src->p0y;
dst->p1y = src->p1y;
dst->p2y = src->p2y;
dst->p3y = src->p3y;
}
/**
* Rotate the point according given rotation angle rotation center is 0,0
*/
static void _rotate_point(int32_t angle, int32_t * x, int32_t * y)
{
int32_t ori_x = *x;
int32_t ori_y = *y;
int16_t alpha = (int16_t)angle;
*x = ((lv_trigo_cos(alpha) * ori_x) / LV_TRIGO_SIN_MAX) - ((lv_trigo_sin(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
*y = ((lv_trigo_sin(alpha) * ori_x) / LV_TRIGO_SIN_MAX) + ((lv_trigo_cos(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
}
/**
* Set full arc control points depending on quarter.
* Control points match the best approximation of a circle.
* Arc Quarter position is:
* Q2 | Q3
* ---+---
* Q1 | Q0
*/
static void _set_full_arc(vg_arc * fullarc)
{
/* the tangent lenght for the bezier circle approx */
float tang = ((float)fullarc->rad) * BEZIER_OPTIM_CIRCLE;
switch(fullarc->quarter) {
case 0:
/* first quarter */
fullarc->p0x = fullarc->rad;
fullarc->p0y = 0;
fullarc->p1x = fullarc->rad;
fullarc->p1y = (int32_t)tang;
fullarc->p2x = (int32_t)tang;
fullarc->p2y = fullarc->rad;
fullarc->p3x = 0;
fullarc->p3y = fullarc->rad;
break;
case 1:
/* second quarter */
fullarc->p0x = 0;
fullarc->p0y = fullarc->rad;
fullarc->p1x = 0 - (int32_t)tang;
fullarc->p1y = fullarc->rad;
fullarc->p2x = 0 - fullarc->rad;
fullarc->p2y = (int32_t)tang;
fullarc->p3x = 0 - fullarc->rad;
fullarc->p3y = 0;
break;
case 2:
/* third quarter */
fullarc->p0x = 0 - fullarc->rad;
fullarc->p0y = 0;
fullarc->p1x = 0 - fullarc->rad;
fullarc->p1y = 0 - (int32_t)tang;
fullarc->p2x = 0 - (int32_t)tang;
fullarc->p2y = 0 - fullarc->rad;
fullarc->p3x = 0;
fullarc->p3y = 0 - fullarc->rad;
break;
case 3:
/* fourth quarter */
fullarc->p0x = 0;
fullarc->p0y = 0 - fullarc->rad;
fullarc->p1x = (int32_t)tang;
fullarc->p1y = 0 - fullarc->rad;
fullarc->p2x = fullarc->rad;
fullarc->p2y = 0 - (int32_t)tang;
fullarc->p3x = fullarc->rad;
fullarc->p3y = 0;
break;
default:
LV_ASSERT_MSG(false, "Invalid arc quarter.");
break;
}
}
/**
* Linear interpolation between two points 'a' and 'b'
* 't' parameter is the proportion ratio expressed in range [0 ; T_FRACTION ]
*/
static inline float _lerp(float coord_a, float coord_b, uint16_t t)
{
float tf = (float)t;
return ((T_FRACTION - tf) * coord_a + tf * coord_b) / T_FRACTION;
}
/**
* Computes a point of bezier curve given 't' param
*/
static inline float _comp_bezier_point(float t, cubic_cont_pt cp)
{
float t_sq = t * t;
float inv_t_sq = (1.0f - t) * (1.0f - t);
float apt = (1.0f - t) * inv_t_sq * cp.p0 + 3.0f * inv_t_sq * t * cp.p1 + 3.0f * (1.0f - t) * t_sq * cp.p2 + t * t_sq *
cp.p3;
return apt;
}
/**
* Find parameter 't' in curve at point 'pt'
* proceed by dichotomy on only 1 dimension,
* works only if the curve is monotonic
* bezier curve is defined by control points [p0 p1 p2 p3]
* 'dec' tells if curve is decreasing (true) or increasing (false)
*/
static uint16_t _get_bez_t_from_pos(float pt, cubic_cont_pt cp, bool dec)
{
/* initialize dichotomy with boundary 't' values */
float t_low = 0.0f;
float t_mid = 0.5f;
float t_hig = 1.0f;
float a_pt;
/* dichotomy loop */
for(int i = 0; i < DICHOTO_ITER; i++) {
a_pt = _comp_bezier_point(t_mid, cp);
/* check mid-point position on bezier curve versus targeted point */
if((a_pt > pt) != dec) {
t_hig = t_mid;
}
else {
t_low = t_mid;
}
/* define new 't' param for mid-point */
t_mid = (t_low + t_hig) / 2.0f;
}
/* return parameter 't' in integer range [0 ; T_FRACTION] */
return (uint16_t)floorf(t_mid * T_FRACTION + 0.5f);
}
/**
* Gives relative coords of the control points
* for the sub-arc starting at angle with given angle span
*/
static void _get_subarc_control_points(vg_arc * arc, int32_t span)
{
vg_arc fullarc = {0};
fullarc.angle = arc->angle;
fullarc.quarter = arc->quarter;
fullarc.rad = arc->rad;
_set_full_arc(&fullarc);
/* special case of full arc */
if(arc->angle == 90) {
_copy_arc(arc, &fullarc);
return;
}
/* compute 1st arc using the geometric construction of curve */
uint16_t t2 = TperDegree[arc->angle + span];
/* lerp for A */
float a2x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t2);
float a2y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t2);
/* lerp for B */
float b2x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t2);
float b2y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t2);
/* lerp for C */
float c2x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t2);
float c2y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t2);
/* lerp for D */
float d2x = _lerp(a2x, b2x, t2);
float d2y = _lerp(a2y, b2y, t2);
/* lerp for E */
float e2x = _lerp(b2x, c2x, t2);
float e2y = _lerp(b2y, c2y, t2);
float pt2x = _lerp(d2x, e2x, t2);
float pt2y = _lerp(d2y, e2y, t2);
/* compute sub-arc using the geometric construction of curve */
uint16_t t1 = TperDegree[arc->angle];
/* lerp for A */
float a1x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t1);
float a1y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t1);
/* lerp for B */
float b1x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t1);
float b1y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t1);
/* lerp for C */
float c1x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t1);
float c1y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t1);
/* lerp for D */
float d1x = _lerp(a1x, b1x, t1);
float d1y = _lerp(a1y, b1y, t1);
/* lerp for E */
float e1x = _lerp(b1x, c1x, t1);
float e1y = _lerp(b1y, c1y, t1);
float pt1x = _lerp(d1x, e1x, t1);
float pt1y = _lerp(d1y, e1y, t1);
/* find the 't3' parameter for point P(t1) on the sub-arc [P0 A2 D2 P(t2)] using dichotomy
* use position of x axis only */
uint16_t t3;
t3 = _get_bez_t_from_pos(pt1x,
(cubic_cont_pt) {
.p0 = ((float)fullarc.p0x), .p1 = a2x, .p2 = d2x, .p3 = pt2x
},
(bool)(pt2x < (float)fullarc.p0x));
/* lerp for B */
float b3x = _lerp(a2x, d2x, t3);
float b3y = _lerp(a2y, d2y, t3);
/* lerp for C */
float c3x = _lerp(d2x, pt2x, t3);
float c3y = _lerp(d2y, pt2y, t3);
/* lerp for E */
float e3x = _lerp(b3x, c3x, t3);
float e3y = _lerp(b3y, c3y, t3);
arc->p0x = (int32_t)floorf(0.5f + pt1x);
arc->p0y = (int32_t)floorf(0.5f + pt1y);
arc->p1x = (int32_t)floorf(0.5f + e3x);
arc->p1y = (int32_t)floorf(0.5f + e3y);
arc->p2x = (int32_t)floorf(0.5f + c3x);
arc->p2y = (int32_t)floorf(0.5f + c3y);
arc->p3x = (int32_t)floorf(0.5f + pt2x);
arc->p3y = (int32_t)floorf(0.5f + pt2y);
}
/**
* Gives relative coords of the control points
*/
static void _get_arc_control_points(vg_arc * arc, bool start)
{
vg_arc fullarc = {0};
fullarc.angle = arc->angle;
fullarc.quarter = arc->quarter;
fullarc.rad = arc->rad;
_set_full_arc(&fullarc);
/* special case of full arc */
if(arc->angle == 90) {
_copy_arc(arc, &fullarc);
return;
}
/* compute sub-arc using the geometric construction of curve */
uint16_t t = TperDegree[arc->angle];
/* lerp for A */
float ax = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t);
float ay = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t);
/* lerp for B */
float bx = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t);
float by = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t);
/* lerp for C */
float cx = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t);
float cy = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t);
/* lerp for D */
float dx = _lerp(ax, bx, t);
float dy = _lerp(ay, by, t);
/* lerp for E */
float ex = _lerp(bx, cx, t);
float ey = _lerp(by, cy, t);
/* sub-arc's control points are tangents of DeCasteljau's algorithm */
if(start) {
arc->p0x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
arc->p0y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
arc->p1x = (int32_t)floorf(0.5f + ex);
arc->p1y = (int32_t)floorf(0.5f + ey);
arc->p2x = (int32_t)floorf(0.5f + cx);
arc->p2y = (int32_t)floorf(0.5f + cy);
arc->p3x = fullarc.p3x;
arc->p3y = fullarc.p3y;
}
else {
arc->p0x = fullarc.p0x;
arc->p0y = fullarc.p0y;
arc->p1x = (int32_t)floorf(0.5f + ax);
arc->p1y = (int32_t)floorf(0.5f + ay);
arc->p2x = (int32_t)floorf(0.5f + dx);
arc->p2y = (int32_t)floorf(0.5f + dy);
arc->p3x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
arc->p3y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
}
}
/**
* Add the arc control points into the path data for vglite,
* taking into account the real center of the arc (translation).
* arc_path: (in/out) the path data array for vglite
* pidx: (in/out) index of last element added in arc_path
* q_arc: (in) the arc data containing control points
* 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, 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++] = VLC_OP_LINE;
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;
#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;
#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++] = VLC_OP_LINE;
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;
#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;
#endif
}
/* update index i n path array*/
*pidx = idx;
}
static void _add_arc_path(int32_t * arc_path, int * pidx, int32_t radius,
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;
int32_t start_arc_angle = start_angle % 90;
int32_t end_arc_angle = end_angle % 90;
int32_t inv_start_arc_angle = (start_arc_angle > 0) ? (90 - start_arc_angle) : 0;
int32_t nbarc = (end_angle - start_angle - inv_start_arc_angle - end_arc_angle) / 90;
q_arc.rad = radius;
/* handle special case of start & end point in the same quarter */
if(((start_angle / 90) == (end_angle / 90)) && (nbarc <= 0)) {
q_arc.quarter = (start_angle / 90) % 4;
q_arc.angle = start_arc_angle;
_get_subarc_control_points(&q_arc, end_arc_angle - start_arc_angle);
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
return;
}
if(cw) {
/* partial starting arc */
if(start_arc_angle > 0) {
q_arc.quarter = (start_angle / 90) % 4;
q_arc.angle = start_arc_angle;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, true);
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
/* full arcs */
for(int32_t q = 0; q < nbarc ; q++) {
q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
q_arc.angle = 90;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
/* partial ending arc */
if(end_arc_angle > 0) {
q_arc.quarter = (end_angle / 90) % 4;
q_arc.angle = end_arc_angle;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, false);
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
}
else { /* counter clockwise */
/* partial ending arc */
if(end_arc_angle > 0) {
q_arc.quarter = (end_angle / 90) % 4;
q_arc.angle = end_arc_angle;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, false);
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
/* full arcs */
for(int32_t q = nbarc - 1; q >= 0; q--) {
q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
q_arc.angle = 90;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
/* partial starting arc */
if(start_arc_angle > 0) {
q_arc.quarter = (start_angle / 90) % 4;
q_arc.angle = start_arc_angle;
/* get cubic points relative to center */
_get_arc_control_points(&q_arc, true);
/* put cubic points in arc_path */
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
}
}
}
static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_area,
const lv_draw_arc_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_path_t path;
uint16_t start_angle = dsc->start_angle;
uint16_t end_angle = dsc->end_angle;
bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false;
vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
/* path: max size = 16 cubic bezier (7 words each) */
int32_t arc_path[16 * 7];
lv_memset(arc_path, 0, sizeof(arc_path));
/*** Init path ***/
lv_coord_t width = dsc->width; /* inner arc radius = outer arc radius - width */
uint16_t radius = dsc->radius;
if(width > radius)
width = radius;
int pidx = 0;
int32_t cp_x, cp_y; /* control point coords */
/* first control point of curve */
cp_x = radius;
cp_y = 0;
_rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_MOVE;
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, center, true);
if(donut) {
/* close outer circle */
cp_x = radius;
cp_y = 0;
_rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE;
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++] = 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 = {center->x + cp_x, center->y + cp_y};
_add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180),
&round_center, true);
}
else { /* 1st flat ending */
cp_x = radius - width;
cp_y = 0;
_rotate_point(end_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE;
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, center, false);
/* last control point of curve */
if(donut) { /* close the loop */
cp_x = radius - width;
cp_y = 0;
_rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE;
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 = {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);
}
else { /* 2nd flat ending */
cp_x = radius;
cp_y = 0;
_rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE;
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)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed.");
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
vglite_set_scissor(clip_area);
/*** Draw arc ***/
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw arc failed.");
vglite_run();
vglite_disable_scissor();
err = vg_lite_clear_path(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed.");
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,114 @@
/**
* @file lv_draw_vglite_bg_img.c
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->src == NULL) return;
if(dsc->opa <= LV_OPA_MIN) return;
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
return;
}
const lv_area_t * clip_area_ori = draw_unit->clip_area;
draw_unit->clip_area = &clip_area;
lv_image_src_t src_type = lv_image_src_get_type(dsc->src);
if(src_type == LV_IMAGE_SRC_SYMBOL) {
lv_point_t size;
lv_text_get_size(&size, dsc->src, dsc->font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
lv_area_t a;
a.x1 = coords->x1 + lv_area_get_width(coords) / 2 - size.x / 2;
a.x2 = a.x1 + size.x - 1;
a.y1 = coords->y1 + lv_area_get_height(coords) / 2 - size.y / 2;
a.y2 = a.y1 + size.y - 1;
lv_draw_label_dsc_t label_draw_dsc;
lv_draw_label_dsc_init(&label_draw_dsc);
label_draw_dsc.font = dsc->font;
label_draw_dsc.color = dsc->recolor;
label_draw_dsc.opa = dsc->opa;
label_draw_dsc.text = dsc->src;
lv_draw_vglite_label(draw_unit, &label_draw_dsc, &a);
}
else {
lv_draw_image_dsc_t img_dsc;
lv_draw_image_dsc_init(&img_dsc);
img_dsc.recolor = dsc->recolor;
img_dsc.recolor_opa = dsc->recolor_opa;
img_dsc.opa = dsc->opa;
img_dsc.src = dsc->src;
/*Center align*/
if(dsc->tiled == false) {
lv_area_t area;
area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - dsc->img_header.w / 2;
area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - dsc->img_header.h / 2;
area.x2 = area.x1 + dsc->img_header.w - 1;
area.y2 = area.y1 + dsc->img_header.h - 1;
lv_draw_vglite_img(draw_unit, &img_dsc, &area);
}
else {
lv_area_t area;
area.y1 = coords->y1;
area.y2 = area.y1 + dsc->img_header.h - 1;
for(; area.y1 <= coords->y2; area.y1 += dsc->img_header.h, area.y2 += dsc->img_header.h) {
area.x1 = coords->x1;
area.x2 = area.x1 + dsc->img_header.w - 1;
for(; area.x1 <= coords->x2; area.x1 += dsc->img_header.w, area.x2 += dsc->img_header.w) {
lv_draw_vglite_img(draw_unit, &img_dsc, &area);
}
}
}
}
draw_unit->clip_area = clip_area_ori;
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,175 @@
/**
* @file lv_draw_vglite_border.c
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_path.h"
#include "lv_vglite_utils.h"
#include <math.h>
/*********************
* DEFINES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* 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
*
*/
static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_border_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
if(dsc->side == (lv_border_side_t)LV_BORDER_SIDE_NONE)
return;
lv_layer_t * layer = draw_unit->target_layer;
lv_area_t rel_coords;
lv_coord_t width = dsc->width;
/* Move border inwards to align with software rendered border */
rel_coords.x1 = coords->x1 + ceil(width / 2.0f);
rel_coords.x2 = coords->x2 - floor(width / 2.0f);
rel_coords.y1 = coords->y1 + ceil(width / 2.0f);
rel_coords.y2 = coords->y2 - floor(width / 2.0f);
/* Move outline outwards to align with software rendered outline */
//lv_coord_t outline_pad = dsc->outline_pad - 1;
//rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f);
//rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f);
//rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f);
//rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f);
lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t clipped_coords;
if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
return; /*Fully clipped, nothing to do*/
_vglite_draw_border(&rel_coords, &rel_clip_area, dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_border_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
lv_coord_t radius = dsc->radius;
vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
if(radius < 0)
return;
lv_coord_t border_half = (lv_coord_t)floor(dsc->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;
/*** Init path ***/
int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
uint32_t path_data_size;
vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
vg_lite_quality_t path_quality = radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM;
vg_lite_path_t path;
err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed.");
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_coord_t line_width = dsc->width;
/*** Draw border ***/
err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set draw path type failed.");
err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set stroke failed.");
err = vg_lite_update_stroke(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update stroke failed.");
vglite_set_scissor(clip_area);
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw border failed.");
vglite_run();
vglite_disable_scissor();
err = vg_lite_clear_path(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed.");
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,259 @@
/**
* @file lv_draw_vglite_fill.c
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_path.h"
#include "lv_vglite_utils.h"
#include "../../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* Fill area, with optional opacity.
*
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dsc Description of the area to fill (color, opa)
*
*/
static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * dsc);
/**
* 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
*
*/
static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_fill_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
lv_layer_t * layer = draw_unit->target_layer;
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;
//}
lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t clipped_coords;
if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
return; /*Fully clipped, nothing to do*/
/*
* Most simple case: just a plain rectangle (no radius, no gradient)
*/
if((dsc->radius == 0) && (dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE))
_vglite_fill(&clipped_coords, dsc);
else
_vglite_draw_rect(&rel_coords, &rel_clip_area, dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/
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)
};
err = vg_lite_clear(vgbuf, &rect, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear failed.");
vglite_run();
}
else { /*fill with transparency*/
vg_lite_path_t path;
int32_t path_data[] = { /*VG rectangular path*/
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_MEDIUM, sizeof(path_data), path_data,
(vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1,
((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
/*Draw rectangle*/
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw rectangle failed.");
vglite_run();
err = vg_lite_clear_path(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed.");
}
}
static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_fill_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
lv_coord_t radius = dsc->radius;
vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
if(dsc->radius < 0)
return;
/*** Init path ***/
int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
uint32_t path_data_size;
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_MEDIUM;
vg_lite_path_t path;
err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
/*** Init Color ***/
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
vglite_set_scissor(clip_area);
vg_lite_linear_gradient_t gradient;
bool has_gradient = (dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE);
/*** Init Gradient ***/
if(has_gradient) {
vg_lite_matrix_t * grad_matrix;
uint32_t colors[2];
uint32_t stops[2];
lv_color32_t col32[2];
/* Gradient setup */
uint8_t cnt = LV_MAX(dsc->grad.stops_count, 2);
for(uint8_t i = 0; i < cnt; i++) {
stops[i] = dsc->grad.stops[i].frac;
col32[i] = lv_color_to_32(dsc->grad.stops[i].color, dsc->opa);
colors[i] = vglite_get_color(col32[i], true);
}
lv_memset(&gradient, 0, sizeof(vg_lite_linear_gradient_t));
err = vg_lite_init_grad(&gradient);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init gradient failed");
err = vg_lite_set_grad(&gradient, cnt, colors, stops);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set gradient failed.");
err = vg_lite_update_grad(&gradient);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update gradient failed.");
grad_matrix = vg_lite_get_grad_matrix(&gradient);
vg_lite_identity(grad_matrix);
vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix);
if(dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix);
vg_lite_rotate(90.0f, grad_matrix);
}
else { /*LV_GRAD_DIR_HOR*/
vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix);
}
err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw gradient failed.");
}
else {
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw rectangle failed.");
}
vglite_run();
vglite_disable_scissor();
err = vg_lite_clear_path(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed.");
if(has_gradient) {
err = vg_lite_clear_grad(&gradient);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear gradient failed.");
}
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,412 @@
/**
* @file lv_draw_vglite_blend.c
*
*/
/**
* Copyright 2020-2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_matrix.h"
#include "lv_vglite_utils.h"
#include "../../../misc/lv_log.h"
/*********************
* DEFINES
*********************/
#if VGLITE_BLIT_SPLIT_ENABLED
/**
* BLIT split threshold - BLITs with width or height higher than this value will
* be done in multiple steps. Value must be multiple of stride alignment in px.
* For most color formats the alignment is 16px (except the index formats).
*/
#define VGLITE_BLIT_SPLIT_THR 352
/* Enable for logging debug traces. */
#define VGLITE_LOG_TRACE 0
#if VGLITE_LOG_TRACE
#define VGLITE_TRACE(fmt, ...) \
do { \
LV_LOG(fmt, ##__VA_ARGS__); \
} while (0)
#else
#define VGLITE_TRACE(fmt, ...) \
do { \
} while (0)
#endif
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* 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] dest_area Destination area with relative coordinates to dest buffer
* @param[in] src_area Source area with relative coordinates to src buffer
* @param[in] opa Opacity
*
*/
static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa);
#if VGLITE_BLIT_SPLIT_ENABLED
/**
* Move buffer pointer as close as possible to area, but with respect to alignment requirements.
*
* @param[in] buf Buffer address pointer
* @param[in] area Area with relative coordinates to the buffer
* @param[in] stride Stride of buffer in bytes
* @param[in] cf Color format of buffer
*/
static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stride, lv_color_format_t cf);
/**
* BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects.
* By default, image is copied directly, with optional opacity.
*
* @param dest_buf Destination buffer
* @param[in] dest_area Destination area with relative coordinates to dest buffer
* @param[in] dest_stride Stride of destination buffer in bytes
* @param[in] dest_cf Color format of destination buffer
* @param[in] src_buf Source buffer
* @param[in] src_area Source area with relative coordinates to src buffer
* @param[in] src_stride Stride of source buffer in bytes
* @param[in] src_cf Color format of source buffer
* @param[in] opa Opacity
*
*/
static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf,
const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf,
lv_opa_t opa);
#else
/**
* BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation.
* By default, image is copied directly, with optional opacity.
*
* @param[in] dest_area Area with relative coordinates to dest buffer
* @param[in] clip_area Clip area with relative coordinates to dest buffer
* @param[in] src_area Source area with relative coordinates to src buffer
* @param[in] dsc Image descriptor
*
*/
static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * clip_area,
const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc);
#endif /*VGLITE_BLIT_SPLIT_ENABLED*/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
lv_layer_t * layer = draw_unit->target_layer;
const lv_image_dsc_t * img_dsc = dsc->src;
lv_area_t rel_coords;
lv_area_copy(&rel_coords, coords);
lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_unit->clip_area);
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_area_t blend_area;
bool has_transform = dsc->rotation != 0 || dsc->zoom != LV_SCALE_NONE;
if(has_transform)
lv_area_copy(&blend_area, &rel_coords);
else if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
return; /*Fully clipped, nothing to do*/
const void * src_buf = img_dsc->data;
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (coords->x1 - layer->draw_buf_ofs.x);
src_area.y1 = blend_area.y1 - (coords->y1 - layer->draw_buf_ofs.y);
src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1;
src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1;
lv_color_format_t src_cf = img_dsc->header.cf;
uint32_t src_stride = img_dsc->header.stride;
/* Set src_vgbuf structure. */
vglite_set_src_buf(src_buf, lv_area_get_width(&src_area), lv_area_get_height(&src_area), src_stride, src_cf);
#if VGLITE_BLIT_SPLIT_ENABLED
void * dest_buf = lv_draw_buf_get_buf(&layer->draw_buf);
uint32_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf);
lv_color_format_t dest_cf = layer->draw_buf.color_format;
if(!has_transform)
_vglite_blit_split(dest_buf, &blend_area, dest_stride, dest_cf,
src_buf, &src_area, src_stride, src_cf, dsc->opa);
#else
if(has_transform)
_vglite_blit_transform(&blend_area, &rel_clip_area, &src_area, dsc);
else
_vglite_blit_single(&blend_area, &src_area, dsc->opa);
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _vglite_blit(const lv_area_t * src_area, lv_opa_t opa)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_buffer_t * dst_vgbuf = vglite_get_dest_buf();
vg_lite_buffer_t * src_vgbuf = vglite_get_src_buf();
uint32_t rect[] = {
(uint32_t)src_area->x1, /* start x */
(uint32_t)src_area->y1, /* start y */
(uint32_t)lv_area_get_width(src_area), /* width */
(uint32_t)lv_area_get_height(src_area) /* height */
};
uint32_t color;
vg_lite_blend_t blend;
if(opa >= (lv_opa_t)LV_OPA_MAX) {
color = 0xFFFFFFFFU;
blend = VG_LITE_BLEND_SRC_OVER;
src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
}
else {
if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
color = (opa << 24) | 0x00FFFFFFU;
}
else {
color = (opa << 24) | (opa << 16) | (opa << 8) | opa;
}
blend = VG_LITE_BLEND_SRC_OVER;
src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
}
vg_lite_matrix_t * vgmatrix = vglite_get_matrix();
err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, vgmatrix, blend, color, VG_LITE_FILTER_POINT);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Blit rectangle failed.");
vglite_run();
}
static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa)
{
/* Set scissor. */
vglite_set_scissor(dest_area);
/* Set vgmatrix. */
vglite_set_translation_matrix(dest_area);
/* Start blit. */
_vglite_blit(src_area, opa);
/* Disable scissor. */
vglite_disable_scissor();
}
#if VGLITE_BLIT_SPLIT_ENABLED
static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stride, lv_color_format_t cf)
{
uint8_t ** buf_u8 = (uint8_t **)buf;
uint8_t align_bytes = vglite_get_alignment(cf);
uint8_t bits_per_pixel = vglite_get_px_size(cf);
uint16_t align_pixels = align_bytes * 8 / bits_per_pixel;
if(area->x1 >= (lv_coord_t)(area->x1 % align_pixels)) {
uint16_t shift_x = area->x1 - (area->x1 % align_pixels);
area->x1 -= shift_x;
area->x2 -= shift_x;
*buf_u8 += (shift_x * bits_per_pixel) / 8;
}
if(area->y1) {
uint16_t shift_y = area->y1;
area->y1 -= shift_y;
area->y2 -= shift_y;
*buf_u8 += shift_y * stride;
}
}
static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf,
const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf,
lv_opa_t opa)
{
VGLITE_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);
/* Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible */
_move_buf_close_to_area((void **)&src_buf, src_area, src_stride, src_cf);
_move_buf_close_to_area(&dest_buf, dest_area, dest_stride, dest_cf);
/* If we're in limit, do a single BLIT */
if((src_area->x2 < VGLITE_BLIT_SPLIT_THR) &&
(src_area->y2 < VGLITE_BLIT_SPLIT_THR)) {
/* Set new dest_vgbuf and src_vgbuf memory addresses */
vglite_set_dest_buf_ptr(dest_buf);
vglite_set_src_buf_ptr(src_buf);
_vglite_blit_single(dest_area, src_area, opa);
VGLITE_TRACE("Single "
"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);
};
/* Split the BLIT into multiple tiles */
VGLITE_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 width = LV_MIN(lv_area_get_width(src_area), lv_area_get_width(dest_area));
lv_coord_t height = LV_MIN(lv_area_get_height(src_area), lv_area_get_height(dest_area));
/* Number of tiles needed */
uint8_t total_tiles_x = (src_area->x1 + width + VGLITE_BLIT_SPLIT_THR - 1) /
VGLITE_BLIT_SPLIT_THR;
uint8_t total_tiles_y = (src_area->y1 + height + VGLITE_BLIT_SPLIT_THR - 1) /
VGLITE_BLIT_SPLIT_THR;
uint16_t shift_src_x = src_area->x1;
uint16_t shift_dest_x = dest_area->x1;
VGLITE_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x);
uint8_t * tile_dest_buf;
lv_area_t tile_dest_area;
const uint8_t * tile_src_buf;
lv_area_t tile_src_area;
for(uint8_t y = 0; y < total_tiles_y; y++) {
/* y1 always start from 0 */
tile_src_area.y1 = 0;
/* Calculate y2 coordinates */
if(y < total_tiles_y - 1)
tile_src_area.y2 = VGLITE_BLIT_SPLIT_THR - 1;
else
tile_src_area.y2 = height - y * VGLITE_BLIT_SPLIT_THR - 1;
/* No vertical shift, dest y is always in sync with src y */
tile_dest_area.y1 = tile_src_area.y1;
tile_dest_area.y2 = tile_src_area.y2;
/* Advance start pointer for every tile, except the first column (y = 0) */
tile_src_buf = (uint8_t *)src_buf + y * VGLITE_BLIT_SPLIT_THR * src_stride;
tile_dest_buf = (uint8_t *)dest_buf + y * VGLITE_BLIT_SPLIT_THR * dest_stride;
for(uint8_t x = 0; x < total_tiles_x; x++) {
/* x1 always start from the same shift */
tile_src_area.x1 = shift_src_x;
tile_dest_area.x1 = shift_dest_x;
if(x > 0) {
/* Advance start pointer for every tile, except the first raw (x = 0) */
tile_src_buf += VGLITE_BLIT_SPLIT_THR * vglite_get_px_size(src_cf) / 8;
tile_dest_buf += VGLITE_BLIT_SPLIT_THR * vglite_get_px_size(dest_cf) / 8;
}
/* Calculate x2 coordinates */
if(x < total_tiles_x - 1)
tile_src_area.x2 = VGLITE_BLIT_SPLIT_THR - 1;
else
tile_src_area.x2 = width - x * VGLITE_BLIT_SPLIT_THR - 1;
tile_dest_area.x2 = tile_src_area.x2;
/* Shift x2 coordinates */
tile_src_area.x2 += shift_src_x;
tile_dest_area.x2 += shift_dest_x;
/* Set new dest_vgbuf and src_vgbuf memory addresses */
vglite_set_dest_buf_ptr(tile_dest_buf);
vglite_set_src_buf_ptr(tile_src_buf);
_vglite_blit_single(&tile_dest_area, &tile_src_area, opa);
VGLITE_TRACE("Tile [%d, %d] "
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
"Size: ([%dx%d] -> [%dx%d]) | "
"Addr: (0x%x -> 0x%x)",
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);
}
}
}
#else
static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * clip_area,
const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc)
{
/* Set scissor. */
vglite_set_scissor(clip_area);
/* Set vgmatrix. */
vglite_set_transformation_matrix(dest_area, dsc);
/* Start blit. */
_vglite_blit(src_area, dsc->opa);
/* Disable scissor. */
vglite_disable_scissor();
}
#endif /*VGLITE_BLIT_SPLIT_ENABLED*/
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,206 @@
/**
* @file lv_draw_vglite_label.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_matrix.h"
#include "lv_vglite_utils.h"
#include "../../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc,
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area);
/**
* Draw letter (character bitmap blend) with optional color and opacity
*
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] mask_buf Mask buffer
* @param[in] mask_area Mask area with relative coordinates of source buffer
* @param[in] mask_stride Stride of mask buffer in bytes
* @param[in] color Color
* @param[in] opa Opacity
*
*/
static void _vglite_draw_letter(const lv_area_t * dest_area,
const void * mask_buf, const lv_area_t * mask_area, uint32_t mask_stride,
lv_color_t color, lv_opa_t opa);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* GLOBAL VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN) return;
lv_draw_label_interate_letters(draw_unit, dsc, coords, _draw_vglite_letter);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc,
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area)
{
if(glyph_draw_dsc) {
if(glyph_draw_dsc->bitmap == NULL) {
#if LV_USE_FONT_PLACEHOLDER
/* Draw a placeholder rectangle*/
lv_draw_border_dsc_t border_draw_dsc;
lv_draw_border_dsc_init(&border_draw_dsc);
border_draw_dsc.opa = glyph_draw_dsc->opa;
border_draw_dsc.color = glyph_draw_dsc->color;
border_draw_dsc.width = 1;
lv_draw_vglite_border(draw_unit, &border_draw_dsc, glyph_draw_dsc->bg_coords);
#endif
}
else if(glyph_draw_dsc->format == LV_DRAW_LETTER_BITMAP_FORMAT_A8) {
/*Do not draw transparent things*/
if(glyph_draw_dsc->opa <= LV_OPA_MIN)
return;
lv_layer_t * layer = draw_unit->target_layer;
lv_area_t blend_area;
if(!_lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, draw_unit->clip_area))
return;
lv_area_move(&blend_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
//void * dest_buf = lv_draw_buf_go_to_xy(&layer->draw_buf,
// blend_area.x1 - layer->draw_buf_ofs.x,
// blend_area.y1 - layer->draw_buf_ofs.y);
const uint8_t * mask_buf = glyph_draw_dsc->bitmap;
lv_area_t mask_area;
lv_area_copy(&mask_area, glyph_draw_dsc->letter_coords);
lv_area_move(&mask_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
uint32_t mask_stride = lv_draw_buf_width_to_stride(
lv_area_get_width(glyph_draw_dsc->letter_coords),
LV_COLOR_FORMAT_A8);
if(mask_buf) {
mask_buf += mask_stride * (blend_area.y1 - glyph_draw_dsc->letter_coords->y1) +
(blend_area.x1 - glyph_draw_dsc->letter_coords->x1);
}
if(!vglite_buf_aligned(mask_buf, mask_stride, LV_COLOR_FORMAT_A8)) {
/* Draw a placeholder rectangle*/
lv_draw_border_dsc_t border_draw_dsc;
lv_draw_border_dsc_init(&border_draw_dsc);
border_draw_dsc.opa = glyph_draw_dsc->opa;
border_draw_dsc.color = glyph_draw_dsc->color;
border_draw_dsc.width = 1;
lv_draw_vglite_border(draw_unit, &border_draw_dsc, glyph_draw_dsc->bg_coords);
}
else {
_vglite_draw_letter(&blend_area, mask_buf, &mask_area, mask_stride,
glyph_draw_dsc->color, glyph_draw_dsc->opa);
}
}
else if(glyph_draw_dsc->format == LV_DRAW_LETTER_BITMAP_FORMAT_IMAGE) {
#if LV_USE_IMGFONT
lv_draw_img_dsc_t img_dsc;
lv_draw_img_dsc_init(&img_dsc);
img_dsc.angle = 0;
img_dsc.zoom = LV_ZOOM_NONE;
img_dsc.opa = glyph_draw_dsc->opa;
img_dsc.src = glyph_draw_dsc->bitmap;
lv_draw_vglite_img(draw_unit, &img_dsc, glyph_draw_dsc->letter_coords);
#endif
}
}
if(fill_draw_dsc && fill_area) {
lv_draw_vglite_fill(draw_unit, fill_draw_dsc, fill_area);
}
}
static void _vglite_draw_letter(const lv_area_t * dest_area,
const void * mask_buf, const lv_area_t * mask_area, uint32_t mask_stride,
lv_color_t color, lv_opa_t opa)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_buffer_t * dst_vgbuf = vglite_get_dest_buf();
vg_lite_buffer_t mask_vgbuf;
mask_vgbuf.format = VG_LITE_A8;
mask_vgbuf.tiled = VG_LITE_LINEAR;
mask_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
mask_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
mask_vgbuf.width = (int32_t)lv_area_get_width(mask_area);
mask_vgbuf.height = (int32_t)lv_area_get_height(mask_area);
mask_vgbuf.stride = (int32_t)mask_stride;
lv_memset(&mask_vgbuf.yuv, 0, sizeof(mask_vgbuf.yuv));
mask_vgbuf.memory = (void *)mask_buf;
mask_vgbuf.address = (uint32_t)mask_vgbuf.memory;
mask_vgbuf.handle = NULL;
uint32_t rect[] = {
(uint32_t)0, /* start x */
(uint32_t)0, /* start y */
(uint32_t)lv_area_get_width(mask_area), /* width */
(uint32_t)lv_area_get_height(mask_area) /* height */
};
lv_color32_t col32 = lv_color_to_32(color, opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
/* Set vgmatrix. */
vglite_set_translation_matrix(dest_area);
vg_lite_matrix_t * vgmatrix = vglite_get_matrix();
/*Blit with font color as paint color*/
err = vg_lite_blit_rect(dst_vgbuf, &mask_vgbuf, rect, vgmatrix, VG_LITE_BLEND_SRC_OVER, vgcol,
VG_LITE_FILTER_POINT);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw letter failed.");
vglite_run();
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,71 @@
/**
* @file lv_draw_vglite_layer.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "../../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords)
{
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
/*It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
*In this case just return. */
if(layer_to_draw->draw_buf.buf == NULL)
return;
lv_image_dsc_t img_dsc;
img_dsc.header.w = layer_to_draw->draw_buf.width;
img_dsc.header.h = layer_to_draw->draw_buf.height;
img_dsc.header.cf = layer_to_draw->draw_buf.color_format;
img_dsc.header.always_zero = 0;
img_dsc.data = lv_draw_buf_get_buf(&layer_to_draw->draw_buf);
lv_draw_image_dsc_t new_draw_dsc;
lv_memcpy(&new_draw_dsc, draw_dsc, sizeof(lv_draw_image_dsc_t));
new_draw_dsc.src = &img_dsc;
lv_draw_vglite_img(draw_unit, &new_draw_dsc, coords);
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,158 @@
/**
* @file lv_draw_vglite_line.c
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "lv_vglite_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC 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, ...)
*
*/
static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2,
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc)
{
if(dsc->width == 0)
return;
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(dsc->p1.x == dsc->p2.x && dsc->p1.y == dsc->p2.y)
return;
lv_layer_t * layer = draw_unit->target_layer;
lv_area_t rel_clip_area;
rel_clip_area.x1 = LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width / 2;
rel_clip_area.x2 = LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width / 2;
rel_clip_area.y1 = LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width / 2;
rel_clip_area.y2 = LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width / 2;
if(!_lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_unit->clip_area))
return; /*Fully clipped, nothing to do*/
lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y);
lv_point_t rel_point1 = {dsc->p1.x - layer->draw_buf_ofs.x, dsc->p1.y - layer->draw_buf_ofs.y};
lv_point_t rel_point2 = {dsc->p2.x - layer->draw_buf_ofs.x, dsc->p2.y - layer->draw_buf_ofs.y};
_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2,
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_path_t path;
vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
vg_lite_cap_style_t cap_style = (dsc->round_start || dsc->round_end) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
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 = 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);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed.");
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
vg_lite_color_t vgcol = vglite_get_color(col32, false);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
/*** Draw line ***/
err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set draw path type failed.");
err = vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count,
stroke_dash_phase, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set stroke failed.");
err = vg_lite_update_stroke(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update stroke failed.");
vglite_set_scissor(clip_area);
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw line failed.");
vglite_run();
vglite_disable_scissor();
err = vg_lite_clear_path(&path);
LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed.");
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,117 @@
/**
* @file lv_vglite_buf.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_buf.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_utils.h"
#include "../../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void _set_vgbuf_ptr(vg_lite_buffer_t * vgbuf, void * buf);
/**********************
* STATIC VARIABLES
**********************/
static vg_lite_buffer_t _dest_vgbuf;
static vg_lite_buffer_t _src_vgbuf;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
vg_lite_buffer_t * vglite_get_dest_buf(void)
{
return &_dest_vgbuf;
}
vg_lite_buffer_t * vglite_get_src_buf(void)
{
return &_src_vgbuf;
}
void vglite_set_dest_buf_ptr(void * buf)
{
_set_vgbuf_ptr(&_dest_vgbuf, buf);
}
void vglite_set_src_buf_ptr(const void * buf)
{
_set_vgbuf_ptr(&_src_vgbuf, (void *)buf);
}
void vglite_set_dest_buf(const lv_draw_buf_t * draw_buf)
{
vglite_set_buf(&_dest_vgbuf, draw_buf->buf, draw_buf->width, draw_buf->height,
lv_draw_buf_get_stride(draw_buf), draw_buf->color_format);
}
void vglite_set_src_buf(const void * buf, lv_coord_t width, lv_coord_t height, uint32_t stride,
lv_color_format_t cf)
{
vglite_set_buf(&_src_vgbuf, (void *)buf, width, height, stride, cf);
}
void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf,
lv_coord_t width, lv_coord_t height, uint32_t stride,
lv_color_format_t cf)
{
vg_lite_buffer_format_t vgformat = vglite_get_buf_format(cf);
vgbuf->format = vgformat;
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(&vgbuf->yuv, 0, sizeof(vgbuf->yuv));
vgbuf->memory = buf;
vgbuf->address = (uint32_t)vgbuf->memory;
vgbuf->handle = NULL;
}
/**********************
* STATIC FUNCTIONS
**********************/
static inline void _set_vgbuf_ptr(vg_lite_buffer_t * vgbuf, void * buf)
{
vgbuf->memory = buf;
vgbuf->address = (uint32_t)vgbuf->memory;
}
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,120 @@
/**
* @file lv_vglite_buf.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_VGLITE_BUF_H
#define LV_VGLITE_BUF_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_VGLITE
#include "../../sw/lv_draw_sw.h"
#include "vg_lite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Get vglite destination buffer pointer.
*
* @retval The vglite destination buffer
*
*/
vg_lite_buffer_t * vglite_get_dest_buf(void);
/**
* Get vglite source buffer pointer.
*
* @retval The vglite source buffer
*
*/
vg_lite_buffer_t * 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 vglite_set_dest_buf_ptr(void * buf);
/**
* Set vglite source buffer address only.
*
* @param[in] buf Source buffer address
*
*/
void vglite_set_src_buf_ptr(const void * buf);
/**
* Set vglite target (destination) buffer.
*
* @param[in] draw_buf Destination draw buffer descriptor
*
*/
void vglite_set_dest_buf(const lv_draw_buf_t * draw_buf);
/**
* Set vglite source buffer.
*
* @param[in] buf Source buffer address
* @param[in] width Source buffer width
* @param[in] height Source buffer height
* @param[in] stride Source buffer stride in bytes
* @param[in] cf Source buffer color format
*
*/
void vglite_set_src_buf(const void * buf, lv_coord_t width, lv_coord_t height, uint32_t stride,
lv_color_format_t cf);
/**
* Set vglite buffer.
*
* @param[in] vgbuf Address of the VGLite buffer object
* @param[in] buf Address of the memory for the VGLite buffer
* @param[in] width Buffer width
* @param[in] height Buffer height
* @param[in] stride Buffer stride in bytes
* @param[in] cf Buffer color format
*
*/
void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf,
lv_coord_t width, lv_coord_t height, uint32_t stride,
lv_color_format_t cf);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VGLITE_BUF_H*/

View File

@ -0,0 +1,79 @@
/**
* @file lv_vglite_matrix.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_matrix.h"
#if LV_USE_DRAW_VGLITE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static vg_lite_matrix_t _vgmatrix;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
vg_lite_matrix_t * vglite_get_matrix(void)
{
return &_vgmatrix;
}
void 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);
}
void vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_image_dsc_t * dsc)
{
vglite_set_translation_matrix(dest_area);
bool has_scale = (dsc->zoom != LV_SCALE_NONE);
bool has_rotation = (dsc->rotation != 0);
vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &_vgmatrix);
if(has_rotation)
vg_lite_rotate(dsc->rotation / 10.0f, &_vgmatrix); /* angle is 1/10 degree */
if(has_scale) {
vg_lite_float_t scale = 1.0f * dsc->zoom / LV_SCALE_NONE;
vg_lite_scale(scale, scale, &_vgmatrix);
}
vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &_vgmatrix);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,79 @@
/**
* @file lv_vglite_matrix.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_VGLITE_MATRIX_H
#define LV_VGLITE_MATRIX_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_VGLITE
#include "../../sw/lv_draw_sw.h"
#include "vg_lite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
vg_lite_matrix_t * vglite_get_matrix(void);
/**
* Creates matrix that translates to origin of given destination area.
*
* @param[in] dest_area Area with relative coordinates of destination buffer
*
*/
void 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
*
*/
void vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_image_dsc_t * dsc);
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VGLITE_MATRIX_H*/

View File

@ -0,0 +1,218 @@
/**
* @file lv_vglite_path.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_path.h"
#if LV_USE_DRAW_VGLITE
#include "vg_lite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void 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
**********************/
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,92 @@
/**
* @file lv_vglite_path.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_VGLITE_PATH_H
#define LV_VGLITE_PATH_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_VGLITE
#include "../../sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/* The optimal Bezier control point offset for radial unit
* see: https://spencermortensen.com/articles/bezier-circle/
**/
#define BEZIER_OPTIM_CIRCLE 0.551915024494f
/* Draw lines for control points of Bezier curves */
#define BEZIER_DBG_CONTROL_POINTS 0
/* 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
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* GLOBAL 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
*
*/
void vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
lv_coord_t radius,
const lv_area_t * coords);
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VGLITE_PATH_H*/

View File

@ -0,0 +1,292 @@
/**
* @file lv_vglite_utils.c
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_utils.h"
#if LV_USE_DRAW_VGLITE
#include "lv_vglite_buf.h"
#include "../../../core/lv_refr.h"
#if LV_USE_OS
#include "vg_lite_gpu.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if LV_USE_OS
static volatile bool _cmd_buf_flushed = false;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
#if LV_USE_OS
bool vglite_cmd_buf_is_flushed(void)
{
return _cmd_buf_flushed;
}
#endif
void vglite_run(void)
{
#if LV_USE_OS
vg_lite_gpu_state_t gpu_state = vg_lite_get_gpu_state();
if(gpu_state == VG_LITE_GPU_BUSY) {
_cmd_buf_flushed = false;
return;
}
#endif
/*
* For multithreading version (with OS), we simply flush the command buffer
* and the vglite draw thread will signal the dispatcher for completed tasks.
* Without OS, we process the tasks and signal them as complete one by one.
*/
#if LV_USE_OS
LV_ASSERT_MSG(vg_lite_flush() == VG_LITE_SUCCESS, "Flush failed.");
_cmd_buf_flushed = true;
#else
LV_ASSERT_MSG(vg_lite_finish() == VG_LITE_SUCCESS, "Finish failed.");
#endif
}
vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient)
{
vg_lite_color_t vg_col32;
/* Only pre-multiply color if hardware pre-multiplication is not present */
if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
lv_col32.red = (uint8_t)((lv_col32.red * lv_col32.alpha) >> 8);
lv_col32.green = (uint8_t)((lv_col32.green * lv_col32.alpha) >> 8);
lv_col32.blue = (uint8_t)((lv_col32.blue * lv_col32.alpha) >> 8);
}
if(!gradient)
/* The color is in ABGR8888 format with red channel in the lower 8 bits. */
vg_col32 = ((vg_lite_color_t)lv_col32.alpha << 24) | ((vg_lite_color_t)lv_col32.blue << 16) |
((vg_lite_color_t)lv_col32.green << 8) | (vg_lite_color_t)lv_col32.red;
else
/* The gradient color is in ARGB8888 format with blue channel in the lower 8 bits. */
vg_col32 = ((vg_lite_color_t)lv_col32.alpha << 24) | ((vg_lite_color_t)lv_col32.red << 16) |
((vg_lite_color_t)lv_col32.green << 8) | (vg_lite_color_t)lv_col32.blue;
return vg_col32;
}
vg_lite_blend_t 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;
default:
vg_blend_mode = VG_LITE_BLEND_SRC_OVER;
break;
}
return vg_blend_mode;
}
vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf)
{
vg_lite_buffer_format_t vg_buffer_format = VG_LITE_BGR565;
switch(cf) {
/*<=1 byte (+alpha) formats*/
case LV_COLOR_FORMAT_L8:
vg_buffer_format = VG_LITE_L8;
break;
case LV_COLOR_FORMAT_A8:
vg_buffer_format = VG_LITE_A8;
break;
case LV_COLOR_FORMAT_I1:
vg_buffer_format = VG_LITE_INDEX_1;
break;
case LV_COLOR_FORMAT_I2:
vg_buffer_format = VG_LITE_INDEX_2;
break;
case LV_COLOR_FORMAT_I4:
vg_buffer_format = VG_LITE_INDEX_4;
break;
case LV_COLOR_FORMAT_I8:
vg_buffer_format = VG_LITE_INDEX_8;
break;
/*2 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB565:
vg_buffer_format = VG_LITE_BGR565;
break;
case LV_COLOR_FORMAT_RGB565A8:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
/*3 byte (+alpha) formats*/
case LV_COLOR_FORMAT_RGB888:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
case LV_COLOR_FORMAT_ARGB8888:
vg_buffer_format = VG_LITE_BGRA8888;
break;
case LV_COLOR_FORMAT_XRGB8888:
vg_buffer_format = VG_LITE_BGRX8888;
break;
default:
LV_ASSERT_MSG(false, "Unsupported color format.");
break;
}
return vg_buffer_format;
}
uint8_t vglite_get_px_size(lv_color_format_t cf)
{
uint8_t bits_per_pixel = LV_COLOR_DEPTH;
switch(cf) {
case LV_COLOR_FORMAT_I1:
bits_per_pixel = 1;
break;
case LV_COLOR_FORMAT_I2:
bits_per_pixel = 2;
break;
case LV_COLOR_FORMAT_I4:
bits_per_pixel = 4;
break;
case LV_COLOR_FORMAT_I8:
case LV_COLOR_FORMAT_A8:
case LV_COLOR_FORMAT_L8:
bits_per_pixel = 8;
break;
case LV_COLOR_FORMAT_RGB565:
bits_per_pixel = 16;
break;
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_RGB888:
bits_per_pixel = 24;
break;
case LV_COLOR_FORMAT_ARGB8888:
case LV_COLOR_FORMAT_XRGB8888:
bits_per_pixel = 32;
break;
case LV_COLOR_FORMAT_NATIVE_REVERSED:
bits_per_pixel = LV_COLOR_DEPTH;
break;
default:
LV_ASSERT_MSG(false, "Unsupported buffer format.");
break;
}
return bits_per_pixel;
}
uint8_t vglite_get_alignment(lv_color_format_t cf)
{
uint8_t align_bytes = LV_COLOR_DEPTH / 8 * 16; //16 pixels
switch(cf) {
case LV_COLOR_FORMAT_I1:
case LV_COLOR_FORMAT_I2:
case LV_COLOR_FORMAT_I4:
align_bytes = 8;
break;
case LV_COLOR_FORMAT_I8:
case LV_COLOR_FORMAT_A8:
case LV_COLOR_FORMAT_L8:
align_bytes = 16;
break;
case LV_COLOR_FORMAT_RGB565:
align_bytes = 32;
break;
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_RGB888:
align_bytes = 48;
break;
case LV_COLOR_FORMAT_ARGB8888:
case LV_COLOR_FORMAT_XRGB8888:
align_bytes = 64;
break;
case LV_COLOR_FORMAT_NATIVE_REVERSED:
align_bytes = LV_COLOR_DEPTH / 8 * 16;
break;
default:
LV_ASSERT_MSG(false, "Unsupported buffer format.");
break;
}
return align_bytes;
}
bool vglite_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf)
{
uint8_t align_bytes = vglite_get_alignment(cf);
/* No alignment requirement for destination buffer when using mode VG_LITE_LINEAR */
/* Test for pointer alignment */
if((uintptr_t)buf % align_bytes) {
LV_LOG_ERROR("Buffer address (0x%x) not aligned to %d bytes.",
(size_t)buf, align_bytes);
return false;
}
/* Test for stride alignment */
if(stride % align_bytes) {
LV_LOG_ERROR("Buffer stride (%d bytes) not aligned to %d bytes.",
stride, align_bytes);
return false;
}
return true;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VGLITE*/

View File

@ -0,0 +1,165 @@
/**
* @file lv_vglite_utils.h
*
*/
/**
* Copyright 2022, 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_VGLITE_UTILS_H
#define LV_VGLITE_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_DRAW_VGLITE
#include "../../sw/lv_draw_sw.h"
#include "vg_lite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* Enable scissor and set the clipping box.
*
* @param[in] clip_area Clip area with relative coordinates of destination buffer
*
*/
static inline void vglite_set_scissor(const lv_area_t * clip_area);
/**
* Disable scissor.
*
*/
static inline void vglite_disable_scissor(void);
/**********************
* GLOBAL PROTOTYPES
**********************/
#if LV_USE_OS
/**
* Get VG-Lite command buffer flushed status.
*
*/
bool vglite_cmd_buf_is_flushed(void);
#endif
/**
* Clear cache and flush command to VG-Lite.
*
*/
void vglite_run(void);
/**
* Get vglite color. Premultiplies (if not hw already) and swizzles the given
* LVGL 32bit color to obtain vglite color.
*
* @param[in] lv_col32 The initial LVGL 32bit color
* @param[in] gradient True for gradient color
*
* @retval The vglite 32-bit color value:
*
*/
vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient);
/**
* Get vglite blend mode.
*
* @param[in] lv_blend_mode The LVGL blend mode
*
* @retval The vglite blend mode
*
*/
vg_lite_blend_t vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode);
/**
* Get vglite buffer format.
*
* @param[in] cf Color format
*
* @retval The vglite buffer format
*
*/
vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf);
/**
* Get vglite buffer pixel size.
*
* @param[in] cf Color format
*
* @retval Bits per pixel
*
*/
uint8_t vglite_get_px_size(lv_color_format_t cf);
/**
* Get vglite buffer alignment.
*
* @param[in] cf Color format
*
* @retval Alignment requirement in bytes
*
*/
uint8_t vglite_get_alignment(lv_color_format_t cf);
/**
* Check memory and stride alignment.
*
* @param[in] buf Buffer address
* @param[in] stride Stride of buffer in bytes
* @param[in] cf Color format - to calculate the expected alignment
*
* @retval true Alignment OK
*
*/
bool vglite_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf);
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
static inline void vglite_set_scissor(const lv_area_t * clip_area)
{
vg_lite_enable_scissor();
vg_lite_set_scissor((int32_t)clip_area->x1, (int32_t)clip_area->y1,
(int32_t)lv_area_get_width(clip_area),
(int32_t)lv_area_get_height(clip_area));
}
static inline void vglite_disable_scissor(void)
{
vg_lite_disable_scissor();
}
#endif /*LV_USE_DRAW_VGLITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VGLITE_UTILS_H*/

View File

@ -319,6 +319,24 @@
#endif
#endif
/* Use NXP's VG-Lite GPU on iMX RTxxx platforms. */
#ifndef LV_USE_DRAW_VGLITE
#ifdef CONFIG_LV_USE_DRAW_VGLITE
#define LV_USE_DRAW_VGLITE CONFIG_LV_USE_DRAW_VGLITE
#else
#define LV_USE_DRAW_VGLITE 0
#endif
#endif
/* Use NXP's PXP on iMX RTxxx platforms. */
#ifndef LV_USE_DRAW_PXP
#ifdef CONFIG_LV_USE_DRAW_PXP
#define LV_USE_DRAW_PXP CONFIG_LV_USE_DRAW_PXP
#else
#define LV_USE_DRAW_PXP 0
#endif
#endif
/*=================
* OPERATING SYSTEM
*=================*/

View File

@ -23,6 +23,12 @@
#include "misc/lv_cache_builtin.h"
#include "misc/lv_async.h"
#include "misc/lv_fs.h"
#if LV_USE_DRAW_VGLITE
#include "draw/nxp/vglite/lv_draw_vglite.h"
#endif
#if LV_USE_DRAW_PXP
#include "draw/nxp/pxp/lv_draw_pxp.h"
#endif
/*********************
* DEFINES
@ -137,6 +143,14 @@ void lv_init(void)
lv_draw_sw_init();
#endif
#if LV_USE_DRAW_VGLITE
lv_draw_vglite_init();
#endif
#if LV_USE_DRAW_PXP
lv_draw_pxp_init();
#endif
_lv_obj_style_init();
/*Initialize the screen refresh system*/