feat(gpu): improve NXP's PXP and VGLite accelerators (#3948)

Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com>
Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com>
Signed-off-by: Wenbin Yuan <wenbin.yuan@nxp.com>
Co-authored-by: Stefan Babatie <stefan.babatie@nxp.com>
Co-authored-by: Wenbin Yuan <wenbin.yuan@nxp.com>
This commit is contained in:
nicusorcitu
2023-01-29 00:14:40 +02:00
committed by GitHub
parent a21241d00c
commit 7c7e99604f
31 changed files with 2642 additions and 1696 deletions

View File

@@ -1,6 +1,6 @@
# NXP # NXP
NXP has integrated LVGL into the MCUXpresso SDK packages for several of their general purpose and crossover NXP has integrated LVGL into the MCUXpresso SDK packages for general purpose and crossover microcontrollers, allowing
microcontrollers, allowing easy evaluation and migration into your product design. easy evaluation and migration into your product design.
[Download an SDK for a supported board](https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY) [Download an SDK for a supported board](https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
today and get started with your next GUI application. today and get started with your next GUI application.
@@ -10,42 +10,38 @@ with PXP/VGLite support if the modules are present), no additional integration w
## HW acceleration for NXP iMX RT platforms ## HW acceleration for NXP iMX RT platforms
Depending on the RT platform used, the acceleration can be done by NXP PXP (PiXel Pipeline) and/or the Verisilicon GPU Depending on the RT platform used, the acceleration can be done by NXP PXP (PiXel Pipeline) and/or the Verisilicon GPU
through an API named VGLite. There is a single NXP draw context that covers both GPUs allowing to have enabled either through an API named VGLite. Each accelerator has its own context that allows them to be used individually as well
one or even both at the same time. While enableing both 2D accelerators, the VGLite can be used to accelerate widget simultaneously (in LVGL multithreading mode).
drawing while the PXP accelerated blit and fill operations.
Supported draw callbacks are available in "src/draw/nxp/lv_gpu_nxp.c":
```c
nxp_draw_ctx->base_draw.draw_arc = lv_draw_nxp_arc;
nxp_draw_ctx->base_draw.draw_rect = lv_draw_nxp_rect;
nxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_nxp_img_decoded;
nxp_draw_ctx->blend = lv_draw_nxp_blend;
```
If enabled both GPUs, the PXP is the preffered one to be used for drawing operation. A fallback mechanism is
implemented so that if the feature is not supported by PXP (or if PXP fails), the VGLite will take over to handle the
task. At the end, the CPU will assure that every widget drawing is fully covered (if not already done by GPU).
### PXP accelerator ### PXP accelerator
Several drawing features in LVGL can be offloaded to the PXP engine. The VGLite (if supported) and CPU are available for Several drawing features in LVGL can be offloaded to the PXP engine. The CPU is available for other operations while the
other operations while the PXP is running. An RTOS is required to block the LVGL drawing thread and switch to another PXP is running. RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for
task or suspend the CPU for power savings. power savings.
Supported draw callbacks are available in "src/draw/nxp/pxp/lv_draw_pxp.c":
```c
pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded;
pxp_draw_ctx->blend = lv_draw_pxp_blend;
pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish;
```
#### Features supported: #### Features supported:
All operations can be used in conjunction with optional transparency.
- RGB565 and ARGB8888 color formats - RGB565 and ARGB8888 color formats
- Area fill + optional transparency - Area fill with color
- BLIT (BLock Image Transfer) + optional transparency - BLIT (BLock Image Transfer)
- Color keying + optional transparency
- Recoloring (color tint) + optional transparency
- Image Rotation (90, 180, 270 degree) + optional transparency
- Recoloring (color tint) + Image Rotation (90, 180, 270 degree) + optional transparency
- Screen Rotation (90, 180, 270 degree) - Screen Rotation (90, 180, 270 degree)
- Color keying
- Recoloring (color tint)
- Image Rotation (90, 180, 270 degree)
- RTOS integration layer - RTOS integration layer
- Default FreeRTOS and bare metal code provided - Default FreeRTOS and bare metal code provided
- Combination of recolor and/or rotation + color key/alpha blend/transparency is supported but PXP needs two steps. - Combination of recolor and/or rotation + color key/alpha blend/transparency is supported.
First step is to recolor/rotate the image to a temporarly buffer (please check LV_MEM_SIZE value for allocation limit) That is achieved by PXP in two steps:
and another step is required to handle color keying, alpha chanel or to apply transparency. - First step is to recolor/rotate the image to a temporary buffer (statically allocated)
- Second step is required to handle color keying, alpha channel or to apply transparency
#### Known limitations: #### Known limitations:
- Rotation is not supported for images unaligned to blocks of 16x16 pixels. - Rotation is not supported for images unaligned to blocks of 16x16 pixels.
@@ -78,51 +74,69 @@ and the final output image can look shifted.
#### Project setup: #### Project setup:
- Add PXP related files to project: - Add PXP related files to project:
- src/draw/nxp/pxp/lv_gpu_nxp_pxp.c, src/draw/nxp/pxp/lv_gpu_nxp_pxp.h: init, uninit, run/wait PXP device, log/trace - src/draw/nxp/pxp/lv_draw_pxp.c[.h]: draw context callbacks
- src/draw/nxp/pxp/lv_draw_pxp_blend.c, src/draw/nxp/pxp/lv_draw_pxp_blend.h: fill and blit (w/o transformation) - src/draw/nxp/pxp/lv_draw_pxp_blend.c[.h]: fill and blit (with optional transformation)
- src/draw/nxp/pxp/lv_gpu_nxp_osa.c, src/draw/nxp/pxp/lv_gpu_osa.h: default implementation of OS-specific functions - src/draw/nxp/pxp/lv_gpu_nxp_pxp.c[.h]: init, uninit, run/wait PXP device
(bare metal and FreeRTOS only) - src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c[.h]: OS abstraction (FreeRTOS or bare metal)
- optional, required only if `LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to 1 - optional, required only if `LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to 1
- PXP related code depends on two drivers provided by MCU SDK. These drivers need to be added to project: - PXP related code depends on two drivers provided by MCU SDK. These drivers need to be added to project:
- fsl_pxp.c, fsl_pxp.h: PXP driver - fsl_pxp.c[.h]: PXP driver
- fsl_cache.c, fsl_cache.h: CPU cache handling functions - fsl_cache.c[.h]: CPU cache handling functions
#### Logging: #### Logging:
- By default, LV_GPU_NXP_PXP_LOG_ERRORS is enabled so that any PXP error will be seen on LVGL output - By default, `LV_GPU_NXP_PXP_LOG_ERRORS` is enabled so that any PXP error will be seen on SDK debug console
- For tracing logs about the PXP limitations or size thresholds, the user can enable LV_GPU_NXP_PXP_LOG_TRACES - By default, `LV_GPU_NXP_PXP_LOG_TRACES` is disabled. Enable it for tracing logs (like PXP limitations)
#### Advanced configuration: #### Advanced configuration:
- Implementation depends on multiple OS-specific functions. The struct `lv_nxp_pxp_cfg_t` with callback pointers is - Implementation depends on multiple OS-specific functions. The struct `lv_nxp_pxp_cfg_t` with callback pointers is
used as a parameter for the `lv_gpu_nxp_pxp_init()` function. Default implementation for FreeRTOS and baremetal is used as a parameter for the `lv_gpu_nxp_pxp_init()` function. Default implementation for FreeRTOS and bare metal is
provided in lv_gpu_nxp_osa.c provided in lv_gpu_nxp_pxp_osa.c
- `pxp_interrupt_init()`: Initialize PXP interrupt (HW setup, OS setup) - `pxp_interrupt_init()`: Initialize PXP interrupt (HW setup, OS setup)
- `pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup, OS setup) - `pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup, OS setup)
- `pxp_run()`: Start PXP job. Use OS-specific mechanism to block drawing thread. PXP must finish drawing before - `pxp_run()`: Start PXP job. Use OS-specific mechanism to block drawing thread. PXP must finish drawing before
leaving this function. leaving this function.
- There are configurable area thresholds which are used to decide whether the area will be processed by CPU or by PXP. - Area threshold (size limit) is configurable and used to decide whether the area will be processed by PXP or not.
Areas smaller than a defined value will be processed by CPU and those bigger than the threshold will be processed by Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be processed by
PXP. These thresholds may be defined as preprocessor variables. Default values are defined in lv_draw_pxp_blend.h PXP. The threshold is defined as a macro in lv_draw_pxp.c
- `LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT`: size threshold for image BLIT, BLIT with color keying, BLIT with recolor and - `LV_GPU_NXP_PXP_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation)
BLIT with rotation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT`: size threshold for image BLIT, BLIT with color keying, BLIT with recolor
and BLIT with rotation and transparency (OPA < LV_OPA_MAX)
- `LV_GPU_NXP_PXP_FILL_SIZE_LIMIT`: size threshold for fill operation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT`: size threshold for fill operation with transparency (OPA < LV_OPA_MAX)
### VGLite accelerator ### VGLite accelerator
Extra drawing features in LVGL can be handled by the VGLite engine. The PXP (if supported) and CPU are available for Extra drawing features in LVGL can be handled by the VGLite engine. The CPU is available for other operations while the
other operations while the VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU
task or suspend the CPU for power savings. for power savings.
Supported draw callbacks are available in "src/draw/nxp/vglite/lv_draw_vglite.c":
```c
vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
vglite_draw_ctx->blend = lv_draw_vglite_blend;
vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
```
#### Features supported: #### Features supported:
All operations can be used in conjunction with optional transparency.
- RGB565 and ARGB8888 color formats - RGB565 and ARGB8888 color formats
- Area fill + optional transparency - Area fill with color
- BLIT (BLock Image Transfer) + optional transparency - BLIT (BLock Image Transfer)
- Image Rotation (any degree with decimal) + optional transparency - Image Rotation (any degree with decimal)
- Image Scale + optional transparency - Image Scale
- Draw background rectangle with radius or gradient - Draw rectangle background with optional radius or gradient
- Draw arc - Blit rectangle background image
- RTOS integration layer - Draw rectangle border/outline with optional rounded corners
- Draw arc with optional rounded ending
- Draw line or dashed line with optional rounded ending
#### Known limitations:
- Source image alignment:
The byte alignment requirement for a pixel depends on the specific pixel format. Both buffer address and buffer stride
must be aligned. As general rule, the alignment is set to 16 pixels. This makes the buffer address alignment to be
32 bytes for RGB565 and 64 bytes for ARGB8888.
- For pixel engine (PE) destination, the alignment should be 64 bytes for all tiled (4x4) buffer layouts.
The pixel engine has no additional alignment requirement for linear buffer layouts (`VG_LITE_LINEAR`).
#### Basic configuration: #### Basic configuration:
- Select NXP VGLite engine in lv_conf.h: Set `LV_USE_GPU_NXP_VG_LITE` to 1 - Select NXP VGLite engine in lv_conf.h: Set `LV_USE_GPU_NXP_VG_LITE` to 1
@@ -130,8 +144,8 @@ task or suspend the CPU for power savings.
#### Basic initialization: #### Basic initialization:
- Initialize VGLite before calling `lv_init()` by specifying the width/height of tessellation window. Value should be - Initialize VGLite before calling `lv_init()` by specifying the width/height of tessellation window. Value should be
a multiple of 16; minimum value is 16 pixels, maximum cannot be greater than frame width. If less than or equal to 0, a multiple of 16; minimum value is 16 pixels, maximum cannot be greater than the frame width. If less than or equal
then no tessellation buffer is created, in which case the function is used for a blit init. to 0, then no tessellation buffer is created, in which case VGLite is initialized only for blitting.
```c ```c
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "vg_lite.h" #include "vg_lite.h"
@@ -144,25 +158,21 @@ task or suspend the CPU for power savings.
#### Project setup: #### Project setup:
- Add VGLite related files to project: - Add VGLite related files to project:
- src/draw/nxp/vglite/lv_gpu_nxp_vglite.c, src/draw/nxp/vglite/lv_gpu_nxp_vglite.h: buffer init, log/trace - src/draw/nxp/vglite/lv_draw_vglite.c[.h]: draw context callbacks
- src/draw/nxp/vglite/lv_draw_vglite_blend.c, src/draw/nxp/vglite/lv_draw_vglite_blend.h: fill and blit - src/draw/nxp/vglite/lv_draw_vglite_blend.c[.h]: fill and blit (with optional transformation)
(w/o transformation) - src/draw/nxp/vglite/lv_draw_vglite_rect.c[.h]: draw rectangle
- src/draw/nxp/vglite/lv_draw_vglite_rect.c, src/draw/nxp/vglite/lv_draw_vglite_rect.h: rectangle draw - src/draw/nxp/vglite/lv_draw_vglite_arc.c[.h]: draw arc
- src/draw/nxp/vglite/lv_draw_vglite_arc.c, src/draw/nxp/vglite/lv_draw_vglite_arc.h: arc draw - src/draw/nxp/vglite/lv_draw_vglite_line.c[.h]: draw line
- src/draw/nxp/vglite/lv_vglite_buf.c[.h]: init/get vglite buffer
- src/draw/nxp/vglite/lv_vglite_utils.c[.h]: function helpers
#### Logging: #### Logging:
- By default, LV_GPU_NXP_VG_LITE_LOG_ERRORS is enabled so that any VGLite error will be seen on LVGL output - By default, `LV_GPU_NXP_VG_LITE_LOG_ERRORS` is enabled so that any VGLite error will be seen on SDK debug console
- For tracing logs about the VGLite limitations, size thresholds or stride alignment, the user can enable - By default, `LV_GPU_NXP_VG_LITE_LOG_TRACES` is disabled. Enable it for tracing logs (like blit split workaround or
LV_GPU_NXP_VG_LITE_LOG_TRACES VGLite fallback to CPU due to any error on the driver)
#### Advanced configuration: #### Advanced configuration:
- There are configurable area thresholds which are used to decide whether the area will be processed by CPU or by - Area threshold (size limit) is configurable and used to decide whether the area will be processed by VGLite or not.
VGLite. Areas smaller than a defined value will be processed by CPU and those bigger than the threshold will be Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be processed by
processed by VGLite. These thresholds may be defined as preprocessor variables. Default values are defined in VGLite. The threshold is defined as a macro in lv_draw_vglite.c
lv_draw_vglite_blend.h - `LV_GPU_NXP_VG_LITE_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation)
- `LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT`: size threshold for image BLIT, BLIT with scale and BLIT with rotation
(OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT`: size threshold for image BLIT, BLIT with scale and BLIT with rotation
and transparency (OPA < LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT`: size threshold for fill operation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT`: size threshold for fill operation with transparency (OPA < LV_OPA_MAX)

View File

@@ -14,7 +14,7 @@ void lv_example_animimg_1(void)
{ {
lv_obj_t * animimg0 = lv_animimg_create(lv_scr_act()); lv_obj_t * animimg0 = lv_animimg_create(lv_scr_act());
lv_obj_center(animimg0); lv_obj_center(animimg0);
lv_animimg_set_src(animimg0, (lv_img_dsc_t **) anim_imgs, 3); lv_animimg_set_src(animimg0, (const void **) anim_imgs, 3);
lv_animimg_set_duration(animimg0, 1000); lv_animimg_set_duration(animimg0, 1000);
lv_animimg_set_repeat_count(animimg0, LV_ANIM_REPEAT_INFINITE); lv_animimg_set_repeat_count(animimg0, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animimg0); lv_animimg_start(animimg0);

View File

@@ -624,6 +624,9 @@ static void refr_area_part(lv_draw_ctx_t * draw_ctx)
{ {
lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr);
if(draw_ctx->init_buf)
draw_ctx->init_buf(draw_ctx);
/* Below the `area_p` area will be redrawn into the draw buffer. /* Below the `area_p` area will be redrawn into the draw buffer.
* In single buffered mode wait here until the buffer is freed.*/ * In single buffered mode wait here until the buffer is freed.*/
if(draw_buf->buf1 && !draw_buf->buf2) { if(draw_buf->buf1 && !draw_buf->buf2) {

View File

@@ -84,6 +84,8 @@ typedef struct _lv_draw_ctx_t {
*/ */
lv_color_format_t color_format; lv_color_format_t color_format;
void (*init_buf)(struct _lv_draw_ctx_t * draw_ctx);
void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
void (*draw_arc)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, void (*draw_arc)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,

View File

@@ -1,415 +0,0 @@
/**
* @file lv_gpu_nxp.c
*
*/
/**
* MIT License
*
* Copyright 2022 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_gpu_nxp.h"
#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE
/*
* allow to use both PXP and VGLITE
* both 2D accelerators can be used at the same time:
* thus VGLITE can be used to accelerate widget drawing
* while PXP accelerates Blit & Fill operations.
*/
#if LV_USE_GPU_NXP_PXP
#include "pxp/lv_draw_pxp_blend.h"
#endif
#if LV_USE_GPU_NXP_VG_LITE
#include "vglite/lv_draw_vglite_blend.h"
#include "vglite/lv_draw_vglite_rect.h"
#include "vglite/lv_draw_vglite_arc.h"
#endif
#if LV_COLOR_DEPTH != 32
#include "../../core/lv_refr.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf);
static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_nxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_init_ctx(drv, draw_ctx);
lv_draw_nxp_ctx_t * nxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
nxp_draw_ctx->base_draw.draw_arc = lv_draw_nxp_arc;
nxp_draw_ctx->base_draw.draw_rect = lv_draw_nxp_rect;
nxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_nxp_img_decoded;
nxp_draw_ctx->blend = lv_draw_nxp_blend;
//nxp_draw_ctx->base_draw.wait_for_finish = lv_draw_nxp_wait_cb;
}
void lv_draw_nxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_deinit_ctx(drv, draw_ctx);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* During rendering, LVGL might initializes new draw_ctxs and start drawing into
* a separate buffer (called layer). If the content to be rendered has "holes",
* e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag.
* It means the renderers should draw into an ARGB buffer.
* With 32 bit color depth it's not a big problem but with 16 bit color depth
* the target pixel format is ARGB8565 which is not supported by the GPU.
* In this case, the NXP callbacks should fallback to SW rendering.
*/
static inline bool need_argb8565_support(lv_draw_ctx_t * draw_ctx)
{
#if LV_COLOR_DEPTH != 32
if(draw_ctx->render_with_alpha) return true;
#endif
return false;
}
static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to fill and the clip area.*/
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
bool done = false;
/*Fill/Blend only non masked, normal blended*/
if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && !need_argb8565_support()) {
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
#if LV_USE_GPU_NXP_VG_LITE
lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area);
lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area);
#endif
const lv_color_t * src_buf = dsc->src_buf;
if(src_buf == NULL) {
#if LV_USE_GPU_NXP_PXP
done = (lv_gpu_nxp_pxp_fill(dest_buf, dest_stride, &blend_area,
dsc->color, dsc->opa) == LV_RES_OK);
if(!done)
PXP_LOG_TRACE("PXP fill failed. Fallback.");
#endif
#if LV_USE_GPU_NXP_VG_LITE
if(!done) {
done = (lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &blend_area,
dsc->color, dsc->opa) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback.");
}
#endif
}
else {
#if LV_USE_GPU_NXP_PXP
done = (lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, dsc->blend_area,
dsc->opa, LV_DISP_ROT_NONE) == LV_RES_OK);
if(!done)
PXP_LOG_TRACE("PXP blit failed. Fallback.");
#endif
#if LV_USE_GPU_NXP_VG_LITE
if(!done) {
lv_gpu_nxp_vglite_blit_info_t blit;
lv_coord_t src_stride = lv_area_get_width(dsc->blend_area);
blit.src = src_buf;
blit.src_width = lv_area_get_width(dsc->blend_area);
blit.src_height = lv_area_get_height(dsc->blend_area);
blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t);
blit.src_area.x1 = (blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1));
blit.src_area.y1 = (blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1));
blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1;
blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1;
blit.dst = dest_buf;
blit.dst_width = dest_width;
blit.dst_height = dest_height;
blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t);
blit.dst_area.x1 = blend_area.x1;
blit.dst_area.y1 = blend_area.y1;
blit.dst_area.x2 = blend_area.x2;
blit.dst_area.y2 = blend_area.y2;
blit.opa = dsc->opa;
blit.zoom = LV_IMG_ZOOM_NONE;
blit.angle = 0;
done = (lv_gpu_nxp_vglite_blit(&blit) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback.");
}
#endif
}
}
if(!done)
lv_draw_sw_blend_basic(draw_ctx, dsc);
}
static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf)
{
/*Use the clip area as draw area*/
lv_area_t draw_area;
lv_area_copy(&draw_area, draw_ctx->clip_area);
bool mask_any = lv_draw_mask_is_any(&draw_area);
#if LV_USE_GPU_NXP_VG_LITE
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
#endif
#if LV_USE_GPU_NXP_PXP
bool scale = (dsc->zoom != LV_IMG_ZOOM_NONE);
#endif
bool done = false;
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to fill and the clip area.*/
if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
const lv_color_t * src_buf = (const lv_color_t *)map_p;
if(!src_buf) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
#if LV_USE_GPU_NXP_PXP
if(!mask_any && !scale && !need_argb8565_support()
#if LV_COLOR_DEPTH!=32
&& !lv_img_cf_has_alpha(cf)
#endif
) {
done = (lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, coords,
dsc, cf) == LV_RES_OK);
if(!done)
PXP_LOG_TRACE("PXP blit transform failed. Fallback.");
}
#endif
#if LV_USE_GPU_NXP_VG_LITE
if(!done && !mask_any && !need_argb8565_support() &&
!lv_img_cf_is_chroma_keyed(cf) && !recolor
#if LV_COLOR_DEPTH!=32
&& !lv_img_cf_has_alpha(cf)
#endif
) {
lv_gpu_nxp_vglite_blit_info_t blit;
lv_coord_t src_stride = lv_area_get_width(coords);
blit.src = src_buf;
blit.src_width = lv_area_get_width(coords);
blit.src_height = lv_area_get_height(coords);
blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t);
blit.src_area.x1 = (blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1));
blit.src_area.y1 = (blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1));
blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1;
blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1;
blit.dst = dest_buf;
blit.dst_width = lv_area_get_width(draw_ctx->buf_area);
blit.dst_height = lv_area_get_height(draw_ctx->buf_area);
blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t);
blit.dst_area.x1 = blend_area.x1;
blit.dst_area.y1 = blend_area.y1;
blit.dst_area.x2 = blend_area.x2;
blit.dst_area.y2 = blend_area.y2;
blit.opa = dsc->opa;
blit.angle = dsc->angle;
blit.pivot = dsc->pivot;
blit.zoom = dsc->zoom;
done = (lv_gpu_nxp_vglite_blit_transform(&blit) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback.");
}
#endif
if(!done)
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
}
static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
bool done = false;
lv_draw_rect_dsc_t nxp_dsc;
lv_memcpy(&nxp_dsc, dsc, sizeof(nxp_dsc));
#if LV_USE_DRAW_MASKS
/* Draw only the shadow */
nxp_dsc.bg_opa = 0;
nxp_dsc.bg_img_opa = 0;
nxp_dsc.border_opa = 0;
nxp_dsc.outline_opa = 0;
lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords);
/* Draw the background */
nxp_dsc.shadow_opa = 0;
nxp_dsc.bg_opa = dsc->bg_opa;
done = (draw_nxp_bg(draw_ctx, &nxp_dsc, coords) == LV_RES_OK);
#endif /*LV_USE_DRAW_MASKS*/
/* Draw the remaining parts */
nxp_dsc.shadow_opa = 0;
if(done)
nxp_dsc.bg_opa = 0;
nxp_dsc.bg_img_opa = dsc->bg_img_opa;
nxp_dsc.border_opa = dsc->border_opa;
nxp_dsc.outline_opa = dsc->outline_opa;
lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords);
}
static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
if(dsc->bg_opa <= LV_OPA_MIN)
return LV_RES_INV;
lv_area_t bg_coords;
lv_area_copy(&bg_coords, coords);
/*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) {
bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
}
lv_area_t clipped_coords;
if(!_lv_area_intersect(&clipped_coords, &bg_coords, draw_ctx->clip_area))
return LV_RES_INV;
lv_grad_dir_t grad_dir = dsc->bg_grad.dir;
lv_color_t bg_color = grad_dir == LV_GRAD_DIR_NONE ? dsc->bg_color : dsc->bg_grad.stops[0].color;
if(bg_color.full == dsc->bg_grad.stops[1].color.full) grad_dir = LV_GRAD_DIR_NONE;
bool mask_any = lv_draw_mask_is_any(&bg_coords);
/*
* Most simple case: just a plain rectangle (no mask, no radius, no gradient)
* shall fallback to lv_draw_sw_blend().
*
* Complex case: gradient or radius but no mask.
*/
if(!mask_any && ((dsc->radius != 0) || (grad_dir != LV_GRAD_DIR_NONE)) && !need_argb8565_support()) {
#if LV_USE_GPU_NXP_VG_LITE
lv_res_t res = lv_gpu_nxp_vglite_draw_bg(draw_ctx, dsc, &bg_coords);
if(res != LV_RES_OK)
VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback.");
return res;
#endif
}
return LV_RES_INV;
}
static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle)
{
bool done = false;
#if LV_USE_DRAW_MASKS
if(dsc->opa <= LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
if(start_angle == end_angle)
return;
#if LV_USE_GPU_NXP_VG_LITE
if(!need_argb8565_support()) {
done = (lv_gpu_nxp_vglite_draw_arc(draw_ctx, dsc, center, (int32_t)radius,
(int32_t)start_angle, (int32_t)end_angle) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback.");
}
#endif
#endif/*LV_USE_DRAW_MASKS*/
if(!done)
lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
}
#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -0,0 +1,244 @@
/**
* @file lv_draw_pxp.c
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_pxp.h"
#if LV_USE_GPU_NXP_PXP
#include "lv_draw_pxp_blend.h"
/*********************
* DEFINES
*********************/
/* Minimum area (in pixels) for PXP blit/fill processing. */
#ifndef LV_GPU_NXP_PXP_SIZE_LIMIT
#define LV_GPU_NXP_PXP_SIZE_LIMIT 5000
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx);
static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf);
static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_pxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_init_ctx(drv, draw_ctx);
lv_draw_pxp_ctx_t * pxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded;
pxp_draw_ctx->blend = lv_draw_pxp_blend;
pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish;
}
void lv_draw_pxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_deinit_ctx(drv, draw_ctx);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* During rendering, LVGL might initializes new draw_ctxs and start drawing into
* a separate buffer (called layer). If the content to be rendered has "holes",
* e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag.
* It means the renderers should draw into an ARGB buffer.
* With 32 bit color depth it's not a big problem but with 16 bit color depth
* the target pixel format is ARGB8565 which is not supported by the GPU.
* In this case, the PXP callbacks should fallback to SW rendering.
*/
static inline bool need_argb8565_support(lv_draw_ctx_t * draw_ctx)
{
#if LV_COLOR_DEPTH != 32
if(draw_ctx->render_with_alpha)
return true;
#endif
return false;
}
static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx)
{
lv_gpu_nxp_pxp_wait();
lv_draw_sw_wait_for_finish(draw_ctx);
}
static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_blend_basic(draw_ctx, dsc);
return;
}
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to draw and the clip area*/
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
if(dsc->mask_buf != NULL || dsc->blend_mode != LV_BLEND_MODE_NORMAL ||
lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT) {
lv_draw_sw_blend_basic(draw_ctx, dsc);
return;
}
/*Fill/Blend only non masked, normal blended*/
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
const lv_color_t * src_buf = dsc->src_buf;
if(src_buf == NULL) {
lv_gpu_nxp_pxp_fill(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa);
}
else {
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1);
src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1);
src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1;
src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1;
lv_coord_t src_stride = lv_area_get_width(dsc->blend_area);
lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride,
dsc->opa, LV_DISP_ROT_NONE);
}
}
static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
const lv_color_t * src_buf = (const lv_color_t *)map_p;
if(!src_buf) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to draw and the clip area.*/
if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_coord_t src_width = lv_area_get_width(coords);
lv_coord_t src_height = lv_area_get_height(coords);
bool has_mask = lv_draw_mask_is_any(&blend_area);
bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE);
bool has_rotation = (dsc->angle != 0);
bool unsup_rotation = false;
if(has_rotation) {
/*
* PXP can only rotate at 90x angles.
*/
if(dsc->angle % 900) {
PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle);
unsup_rotation = true;
}
/*
* PXP is set to process 16x16 blocks to optimize the system for memory
* bandwidth and image processing time.
* The output engine essentially truncates any output pixels after the
* desired number of pixels has been written.
* When rotating a source image and the output is not divisible by the block
* size, the incorrect pixels could be truncated and the final output image
* can look shifted.
*/
if(src_width % 16 || src_height % 16) {
PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16.");
unsup_rotation = true;
}
}
if(has_mask || has_scale || unsup_rotation || lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT
#if LV_COLOR_DEPTH != 32
|| lv_img_cf_has_alpha(cf)
#endif
) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1);
src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1);
src_area.x2 = src_area.x1 + src_width - 1;
src_area.y2 = src_area.y1 + src_height - 1;
lv_coord_t src_stride = lv_area_get_width(coords);
lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride,
dsc, cf);
}
#endif /*LV_USE_GPU_NXP_PXP*/

View File

@@ -1,12 +1,12 @@
/** /**
* @file lv_gpu_nxp.h * @file lv_draw_pxp.h
* *
*/ */
/** /**
* MIT License * MIT License
* *
* Copyright 2022 NXP * Copyright 2022, 2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,8 +27,8 @@
* *
*/ */
#ifndef LV_GPU_NXP_H #ifndef LV_DRAW_PXP_H
#define LV_GPU_NXP_H #define LV_DRAW_PXP_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -38,9 +38,10 @@ extern "C" {
* INCLUDES * INCLUDES
*********************/ *********************/
#include "../../lv_conf_internal.h" #include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE
#include "../sw/lv_draw_sw.h" #if LV_USE_GPU_NXP_PXP
#include "../../sw/lv_draw_sw.h"
/********************* /*********************
* DEFINES * DEFINES
@@ -49,23 +50,23 @@ extern "C" {
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
typedef lv_draw_sw_ctx_t lv_draw_nxp_ctx_t; typedef lv_draw_sw_ctx_t lv_draw_pxp_ctx_t;
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
void lv_draw_nxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); void lv_draw_pxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx);
void lv_draw_nxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); void lv_draw_pxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx);
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ #endif /*LV_USE_GPU_NXP_PXP*/
#ifdef __cplusplus #ifdef __cplusplus
} /*extern "C"*/ } /*extern "C"*/
#endif #endif
#endif /*LV_GPU_NXP_H*/ #endif /*LV_DRAW_PXP_H*/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -34,16 +34,19 @@
#include "lv_draw_pxp_blend.h" #include "lv_draw_pxp_blend.h"
#if LV_USE_GPU_NXP_PXP #if LV_USE_GPU_NXP_PXP
#include "lvgl_support.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
#if LV_COLOR_DEPTH==16 #define PXP_TEMP_BUF_SIZE LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL
#if LV_COLOR_DEPTH == 16
#define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565
#define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565
#define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565
#elif LV_COLOR_DEPTH==32 #elif LV_COLOR_DEPTH == 32
#define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888
#define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888
#define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888
@@ -51,13 +54,6 @@
#error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32.
#endif #endif
#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \
|| defined (_WIN64) || defined (__LP64__) || defined (__LLP64__)
#define ALIGN_SIZE 8
#else
#define ALIGN_SIZE 4
#endif
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@@ -66,63 +62,60 @@
* STATIC PROTOTYPES * STATIC PROTOTYPES
**********************/ **********************/
static LV_ATTRIBUTE_MEM_ALIGN uint8_t temp_buf[PXP_TEMP_BUF_SIZE];
/** /**
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
* with combination of transformation (rotation, scale, recolor) and opacity, alpha channel * with combination of transformation (rotation, scale, recolor) and opacity, alpha channel
* or color keying. This requires two steps. First step is used for transformation into * or color keying. This requires two steps. First step is used for transformation into
* a temporary buffer and the second one will handle the color format or opacity. * a temporary buffer and the second one will handle the color format or opacity.
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_area area to be copied from src_buf to dst_buf * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf source buffer * @param[in] src_buf Source buffer
* @param[in] src_area source area with absolute coordinates to draw on destination buffer * @param[in] src_area Area with relative coordinates of source buffer
* @param[in] dsc image descriptor * @param[in] src_stride Stride of source buffer in pixels
* @param[in] cf color format * @param[in] dsc Image descriptor
* @retval LV_RES_OK Fill completed * @param[in] cf Color format
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
/** /**
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
* with transformation and full opacity. * with transformation and full opacity.
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_area area to be copied from src_buf to dst_buf * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf source buffer * @param[in] src_buf Source buffer
* @param[in] src_area source area with absolute coordinates to draw on destination buffer * @param[in] src_area Area with relative coordinates of source buffer
* @param[in] dsc image descriptor * @param[in] src_stride Stride of source buffer in pixels
* @param[in] cf color format * @param[in] dsc Image descriptor
* @retval LV_RES_OK Fill completed * @param[in] cf Color format
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_coord_t dest_stride, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
/** /**
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
* without transformation but handling color format or opacity. * without transformation but handling color format or opacity.
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_area area to be copied from src_buf to dst_buf * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf source buffer * @param[in] src_buf Source buffer
* @param[in] src_area source area with absolute coordinates to draw on destination buffer * @param[in] src_area Area with relative coordinates of source buffer
* @param[in] dsc image descriptor * @param[in] src_stride Stride of source buffer in pixels
* @param[in] cf color format * @param[in] dsc Image descriptor
* @retval LV_RES_OK Fill completed * @param[in] cf Color format
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_coord_t dest_stride, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@@ -132,45 +125,27 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t *
* MACROS * MACROS
**********************/ **********************/
#define ROUND_UP(x, align) ((x + (align - 1)) & ~(align - 1))
/********************** /**********************
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_t color, lv_opa_t opa) lv_color_t color, lv_opa_t opa)
{ {
uint32_t area_size = lv_area_get_size(fill_area); lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t area_w = lv_area_get_width(fill_area); lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_coord_t area_h = lv_area_get_height(fill_area);
if(opa >= (lv_opa_t)LV_OPA_MAX) { lv_gpu_nxp_pxp_reset();
if(area_size < LV_GPU_NXP_PXP_FILL_SIZE_LIMIT) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_SIZE_LIMIT);
return LV_RES_INV;
}
}
else {
if(area_size < LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT);
return LV_RES_INV;
}
}
PXP_Init(LV_GPU_NXP_PXP_ID);
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
/*OUT buffer configure*/ /*OUT buffer configure*/
pxp_output_buffer_config_t outputConfig = { pxp_output_buffer_config_t outputConfig = {
.pixelFormat = PXP_OUT_PIXEL_FORMAT, .pixelFormat = PXP_OUT_PIXEL_FORMAT,
.interlacedMode = kPXP_OutputProgressive, .interlacedMode = kPXP_OutputProgressive,
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * fill_area->y1 + fill_area->x1), .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
.buffer1Addr = (uint32_t)NULL, .buffer1Addr = (uint32_t)NULL,
.pitchBytes = dest_stride * sizeof(lv_color_t), .pitchBytes = dest_stride * sizeof(lv_color_t),
.width = area_w, .width = dest_w,
.height = area_h .height = dest_h
}; };
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig); PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig);
@@ -189,7 +164,7 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons
}; };
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, area_w, area_h); PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
} }
/*Disable PS, use as color generator*/ /*Disable PS, use as color generator*/
@@ -219,34 +194,19 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons
PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
lv_gpu_nxp_pxp_run(); /*Start PXP task*/ lv_gpu_nxp_pxp_run();
return LV_RES_OK;
} }
lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle) const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
lv_opa_t opa, lv_disp_rot_t angle)
{ {
uint32_t dest_size = lv_area_get_size(dest_area);
lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_coord_t src_w = lv_area_get_width(src_area);
lv_coord_t src_h = lv_area_get_height(src_area);
if(opa >= (lv_opa_t)LV_OPA_MAX) { lv_gpu_nxp_pxp_reset();
if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT);
return LV_RES_INV;
}
}
else {
if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT);
return LV_RES_INV;
}
}
PXP_Init(LV_GPU_NXP_PXP_ID);
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
/* convert rotation angle */ /* convert rotation angle */
pxp_rotate_degree_t pxp_rot; pxp_rotate_degree_t pxp_rot;
@@ -293,19 +253,17 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area,
asBlendConfig.alphaMode = kPXP_AlphaOverride; asBlendConfig.alphaMode = kPXP_AlphaOverride;
PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
} }
lv_coord_t src_stride = lv_area_get_width(src_area);
/*AS buffer - source image*/ /*AS buffer - source image*/
pxp_as_buffer_config_t asBufferConfig = { pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = PXP_AS_PIXEL_FORMAT, .pixelFormat = PXP_AS_PIXEL_FORMAT,
.bufferAddr = (uint32_t)src_buf, .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
.pitchBytes = src_stride * sizeof(lv_color_t) .pitchBytes = src_stride * sizeof(lv_color_t)
}; };
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false); PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false);
@@ -321,162 +279,102 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area,
}; };
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
lv_gpu_nxp_pxp_run(); /* Start PXP task */ lv_gpu_nxp_pxp_run();
return LV_RES_OK;
} }
lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
{ {
uint32_t dest_size = lv_area_get_size(dest_area); bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
bool has_rotation = (dsc->angle != 0);
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) { if(has_recolor || has_rotation) {
if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) { if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT); lv_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
return LV_RES_INV; return;
} }
} else {
else {
if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) {
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT);
return LV_RES_INV;
}
}
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
bool rotation = (dsc->angle != 0);
if(rotation) {
if(dsc->angle != 0 && dsc->angle != 900 && dsc->angle != 1800 && dsc->angle != 2700) {
PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle);
return LV_RES_INV;
}
}
if(recolor || rotation) {
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf))
return lv_gpu_nxp_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf);
else
/*Recolor and/or rotation with alpha or opacity is done in two steps.*/ /*Recolor and/or rotation with alpha or opacity is done in two steps.*/
return lv_gpu_nxp_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); lv_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
return;
}
} }
return lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
} }
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
{ {
lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t temp_area_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area); lv_coord_t temp_area_h = lv_area_get_height(dest_area);
lv_res_t res; const lv_area_t temp_area = {
uint32_t size = dest_w * dest_h * sizeof(lv_color_t);
if(ROUND_UP(size, ALIGN_SIZE) >= LV_MEM_SIZE)
PXP_RETURN_INV("Insufficient memory for temporary buffer. Please increase LV_MEM_SIZE.");
lv_color_t * tmp_buf = (lv_color_t *)lv_malloc(size);
if(!tmp_buf)
PXP_RETURN_INV("Allocating temporary buffer failed.");
const lv_area_t tmp_area = {
.x1 = 0, .x1 = 0,
.y1 = 0, .y1 = 0,
.x2 = dest_w - 1, .x2 = temp_area_w - 1,
.y2 = dest_h - 1 .y2 = temp_area_h - 1
}; };
/*Step 1: Transform with full opacity to temporary buffer*/ /*Step 1: Transform with full opacity to temporary buffer*/
res = lv_gpu_nxp_pxp_blit_cover(tmp_buf, &tmp_area, dest_w, src_buf, src_area, dsc, cf); lv_pxp_blit_cover((lv_color_t *)temp_buf, &temp_area, temp_area_w, src_buf, src_area, src_stride, dsc, cf);
if(res != LV_RES_OK) {
PXP_LOG_TRACE("Blit cover with full opacity failed.");
lv_free(tmp_buf);
return res; /*Step 2: Blit temporary result with required opacity to output*/
} lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, (lv_color_t *)temp_buf, &temp_area, temp_area_w, dsc, cf);
/*Step 2: Blit temporary results with required opacity to output*/
res = lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, tmp_buf, &tmp_area, dsc, cf);
/*Clean-up memory*/
lv_free(tmp_buf);
return res;
} }
static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
lv_coord_t dest_stride, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
const lv_color_t * src_buf, const lv_area_t * src_area,
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
{ {
lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_coord_t src_w = lv_area_get_width(src_area);
lv_coord_t src_h = lv_area_get_height(src_area);
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
bool rotation = (dsc->angle != 0); bool has_rotation = (dsc->angle != 0);
PXP_Init(LV_GPU_NXP_PXP_ID); lv_gpu_nxp_pxp_reset();
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
if(rotation) {
/*
* PXP is set to process 16x16 blocks to optimize the system for memory
* bandwidth and image processing time.
* The output engine essentially truncates any output pixels after the
* desired number of pixels has been written.
* When rotating a source image and the output is not divisible by the block
* size, the incorrect pixels could be truncated and the final output image
* can look shifted.
*/
if(lv_area_get_width(src_area) % 16 || lv_area_get_height(src_area) % 16) {
PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16.");
return LV_RES_INV;
}
if(has_rotation) {
/*Convert rotation angle*/ /*Convert rotation angle*/
pxp_rotate_degree_t pxp_rot; pxp_rotate_degree_t pxp_angle;
switch(dsc->angle) { switch(dsc->angle) {
case 0: case 0:
pxp_rot = kPXP_Rotate0; pxp_angle = kPXP_Rotate0;
break; break;
case 900: case 900:
pxp_rot = kPXP_Rotate90; pxp_angle = kPXP_Rotate90;
break; break;
case 1800: case 1800:
pxp_rot = kPXP_Rotate180; pxp_angle = kPXP_Rotate180;
break; break;
case 2700: case 2700:
pxp_rot = kPXP_Rotate270; pxp_angle = kPXP_Rotate270;
break; break;
default: default:
PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); pxp_angle = kPXP_Rotate0;
return LV_RES_INV;
} }
PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable); PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable);
} }
lv_coord_t src_stride = lv_area_get_width(src_area);
/*AS buffer - source image*/ /*AS buffer - source image*/
pxp_as_buffer_config_t asBufferConfig = { pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = PXP_AS_PIXEL_FORMAT, .pixelFormat = PXP_AS_PIXEL_FORMAT,
.bufferAddr = (uint32_t)src_buf, .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
.pitchBytes = src_stride * sizeof(lv_color_t) .pitchBytes = src_stride * sizeof(lv_color_t)
}; };
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
/*Disable PS buffer*/ /*Disable PS buffer*/
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
if(recolor) if(has_recolor)
/*Use as color generator*/ /*Use as color generator*/
PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor)); PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor));
@@ -492,7 +390,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t
}; };
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
if(recolor || lv_img_cf_has_alpha(cf)) { if(has_recolor || lv_img_cf_has_alpha(cf)) {
/** /**
* Configure Porter-Duff blending. * Configure Porter-Duff blending.
* *
@@ -508,7 +406,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t
.srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha, .srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha,
.dstFactorMode = kPXP_PorterDuffFactorStraight, .dstFactorMode = kPXP_PorterDuffFactorStraight,
.srcFactorMode = kPXP_PorterDuffFactorInversed, .srcFactorMode = kPXP_PorterDuffFactorInversed,
.dstGlobalAlpha = recolor ? dsc->recolor_opa : 0x00, .dstGlobalAlpha = has_recolor ? dsc->recolor_opa : 0x00,
.srcGlobalAlpha = 0xff, .srcGlobalAlpha = 0xff,
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/ .dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
.srcAlphaMode = kPXP_PorterDuffAlphaStraight .srcAlphaMode = kPXP_PorterDuffAlphaStraight
@@ -516,22 +414,19 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t
PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
} }
lv_gpu_nxp_pxp_run(); /*Start PXP task*/ lv_gpu_nxp_pxp_run();
return LV_RES_OK;
} }
static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_coord_t dest_stride, const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
{ {
lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_w = lv_area_get_width(dest_area);
lv_coord_t dest_h = lv_area_get_height(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area);
lv_coord_t src_w = lv_area_get_width(src_area);
lv_coord_t src_h = lv_area_get_height(src_area);
PXP_Init(LV_GPU_NXP_PXP_ID); lv_gpu_nxp_pxp_reset();
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
pxp_as_blend_config_t asBlendConfig = { pxp_as_blend_config_t asBlendConfig = {
.alpha = dsc->opa, .alpha = dsc->opa,
@@ -562,28 +457,26 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t *
asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride; asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride;
} }
PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
} }
lv_coord_t src_stride = lv_area_get_width(src_area);
/*AS buffer - source image*/ /*AS buffer - source image*/
pxp_as_buffer_config_t asBufferConfig = { pxp_as_buffer_config_t asBufferConfig = {
.pixelFormat = PXP_AS_PIXEL_FORMAT, .pixelFormat = PXP_AS_PIXEL_FORMAT,
.bufferAddr = (uint32_t)src_buf, .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
.pitchBytes = src_stride * sizeof(lv_color_t) .pitchBytes = src_stride * sizeof(lv_color_t)
}; };
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
if(lv_img_cf_is_chroma_keyed(cf)) { if(lv_img_cf_is_chroma_keyed(cf)) {
lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY; lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY;
lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY; lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY;
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
if(recolor) { if(has_recolor) {
/* New color key after recoloring */ /* New color key after recoloring */
lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa); lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa);
@@ -591,11 +484,11 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t *
LV_COLOR_SET_G(colorKeyLow, colorKey.ch.green != 0 ? colorKey.ch.green - 1 : 0); LV_COLOR_SET_G(colorKeyLow, colorKey.ch.green != 0 ? colorKey.ch.green - 1 : 0);
LV_COLOR_SET_B(colorKeyLow, colorKey.ch.blue != 0 ? colorKey.ch.blue - 1 : 0); LV_COLOR_SET_B(colorKeyLow, colorKey.ch.blue != 0 ? colorKey.ch.blue - 1 : 0);
#if LV_COLOR_DEPTH==16 #if LV_COLOR_DEPTH == 16
LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f); LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f);
LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f);
LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f);
#else /*LV_COLOR_DEPTH==32*/ #else /*LV_COLOR_DEPTH == 32*/
LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff); LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff);
LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff);
LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff);
@@ -620,9 +513,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t *
}; };
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
lv_gpu_nxp_pxp_run(); /* Start PXP task */ lv_gpu_nxp_pxp_run();
return LV_RES_OK;
} }
#endif /*LV_USE_GPU_NXP_PXP*/ #endif /*LV_USE_GPU_NXP_PXP*/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -48,31 +48,6 @@ extern "C" {
* DEFINES * DEFINES
*********************/ *********************/
#ifndef LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT
/** Minimum area (in pixels) for image copy with 100% opacity to be handled by PXP*/
#define LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT
/** Minimum area (in pixels) for image copy with transparency to be handled by PXP*/
#define LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT
/** Minimum invalidated area (in pixels) to be synchronized by PXP during buffer sync */
#define LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_PXP_FILL_SIZE_LIMIT
/** Minimum area (in pixels) to be filled by PXP with 100% opacity*/
#define LV_GPU_NXP_PXP_FILL_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT
/** Minimum area (in pixels) to be filled by PXP with transparency*/
#define LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT 5000
#endif
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@@ -84,51 +59,49 @@ extern "C" {
/** /**
* Fill area, with optional opacity. * Fill area, with optional opacity.
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] fill_area area to fill * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] color color * @param[in] color Color
* @param[in] opa transparency of the color * @param[in] opa Opacity
* @retval LV_RES_OK Fill completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
lv_color_t color, lv_opa_t opa); lv_color_t color, lv_opa_t opa);
/** /**
* BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects.
* By default, image is copied directly, with optional opacity. This function can also * By default, image is copied directly, with optional opacity. This function can also
* rotate the display output buffer to a specified angle (90x step). * rotate the display output buffer to a specified angle (90x step).
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_area destination area * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf source buffer * @param[in] src_buf Source buffer
* @param[in] src_area source area with absolute coordinates to draw on destination buffer * @param[in] src_area Source area with relative coordinates of source buffer
* @param[in] opa opacity of the result * @param[in] src_stride Stride of source buffer in pixels
* @param[in] angle display rotation angle (90x) * @param[in] opa Opacity
* @retval LV_RES_OK Fill completed * @param[in] angle Display rotation angle (90x)
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle); const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
lv_opa_t opa, lv_disp_rot_t angle);
/** /**
* BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation.
* *
* *
* @param[in/out] dest_buf destination buffer * @param[in/out] dest_buf Destination buffer
* @param[in] dest_area destination area * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride width (stride) of destination buffer in pixels * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf source buffer * @param[in] src_buf Source buffer
* @param[in] src_area source area with absolute coordinates to draw on destination buffer * @param[in] src_area Area with relative coordinates of source buffer
* @param[in] dsc image descriptor * @param[in] src_stride Stride of source buffer in pixels
* @param[in] cf color format * @param[in] dsc Image descriptor
* @retval LV_RES_OK Fill completed * @param[in] cf Color format
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
/********************** /**********************
* MACROS * MACROS

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -50,9 +50,9 @@
**********************/ **********************/
/** /**
* Clean & invalidate cache. * Clean and invalidate cache.
*/ */
static void invalidate_cache(void); static inline void invalidate_cache(void);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@@ -70,16 +70,23 @@ static lv_nxp_pxp_cfg_t * pxp_cfg;
lv_res_t lv_gpu_nxp_pxp_init(void) lv_res_t lv_gpu_nxp_pxp_init(void)
{ {
#if LV_USE_GPU_NXP_PXP_AUTO_INIT
pxp_cfg = lv_gpu_nxp_pxp_get_cfg(); pxp_cfg = lv_gpu_nxp_pxp_get_cfg();
#endif
if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init || !pxp_cfg->pxp_run) if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init ||
!pxp_cfg->pxp_run || !pxp_cfg->pxp_wait)
PXP_RETURN_INV("PXP configuration error."); PXP_RETURN_INV("PXP configuration error.");
PXP_Init(LV_GPU_NXP_PXP_ID); PXP_Init(LV_GPU_NXP_PXP_ID);
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable);
if(pxp_cfg->pxp_interrupt_init() != LV_RES_OK) { if(pxp_cfg->pxp_interrupt_init() != LV_RES_OK) {
PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable);
PXP_Deinit(LV_GPU_NXP_PXP_ID); PXP_Deinit(LV_GPU_NXP_PXP_ID);
PXP_RETURN_INV("PXP interrupt init failed."); PXP_RETURN_INV("PXP interrupt init failed.");
} }
@@ -90,23 +97,38 @@ lv_res_t lv_gpu_nxp_pxp_init(void)
void lv_gpu_nxp_pxp_deinit(void) void lv_gpu_nxp_pxp_deinit(void)
{ {
pxp_cfg->pxp_interrupt_deinit(); pxp_cfg->pxp_interrupt_deinit();
PXP_DisableInterrupts(PXP, kPXP_CompleteInterruptEnable); PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable);
PXP_Deinit(LV_GPU_NXP_PXP_ID); PXP_Deinit(LV_GPU_NXP_PXP_ID);
} }
void lv_gpu_nxp_pxp_reset(void)
{
/* Wait for previous command to complete before resetting the registers. */
lv_gpu_nxp_pxp_wait();
PXP_ResetControl(LV_GPU_NXP_PXP_ID);
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
}
void lv_gpu_nxp_pxp_run(void) void lv_gpu_nxp_pxp_run(void)
{ {
/*Clean & invalidate cache*/
invalidate_cache(); invalidate_cache();
pxp_cfg->pxp_run(); pxp_cfg->pxp_run();
} }
void lv_gpu_nxp_pxp_wait(void)
{
pxp_cfg->pxp_wait();
}
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
static void invalidate_cache(void) static inline void invalidate_cache(void)
{ {
lv_disp_t * disp = _lv_refr_get_disp_refreshing(); lv_disp_t * disp = _lv_refr_get_disp_refreshing();
if(disp->driver->clean_dcache_cb) if(disp->driver->clean_dcache_cb)

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -81,8 +81,11 @@ typedef struct {
/** Callback for PXP interrupt de-initialization*/ /** Callback for PXP interrupt de-initialization*/
void (*pxp_interrupt_deinit)(void); void (*pxp_interrupt_deinit)(void);
/** Callback that should start PXP and wait for operation complete*/ /** Callback for PXP start*/
void (*pxp_run)(void); void (*pxp_run)(void);
/** Callback for waiting of PXP completion*/
void (*pxp_wait)(void);
} lv_nxp_pxp_cfg_t; } lv_nxp_pxp_cfg_t;
/********************** /**********************
@@ -104,10 +107,20 @@ lv_res_t lv_gpu_nxp_pxp_init(void);
void lv_gpu_nxp_pxp_deinit(void); void lv_gpu_nxp_pxp_deinit(void);
/** /**
* Start PXP job and wait for completion. * Reset PXP device.
*/
void lv_gpu_nxp_pxp_reset(void);
/**
* Clear cache and start PXP.
*/ */
void lv_gpu_nxp_pxp_run(void); void lv_gpu_nxp_pxp_run(void);
/**
* Wait for PXP completion.
*/
void lv_gpu_nxp_pxp_wait(void);
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020, 2022 NXP * Copyright 2020, 2022, 2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -65,24 +65,29 @@ static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void);
static void _lv_gpu_nxp_pxp_interrupt_deinit(void); static void _lv_gpu_nxp_pxp_interrupt_deinit(void);
/** /**
* Start the PXP job and wait for task completion. * Start the PXP job.
*/ */
static void _lv_gpu_nxp_pxp_run(void); static void _lv_gpu_nxp_pxp_run(void);
/**
* Wait for PXP completion.
*/
static void _lv_gpu_nxp_pxp_wait(void);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
**********************/ **********************/
#if defined(SDK_OS_FREE_RTOS) #if defined(SDK_OS_FREE_RTOS)
static SemaphoreHandle_t s_pxpIdle; static SemaphoreHandle_t s_pxpIdleSem;
#else
static volatile bool s_pxpIdle;
#endif #endif
static volatile bool s_pxpIdle;
static lv_nxp_pxp_cfg_t pxp_default_cfg = { static lv_nxp_pxp_cfg_t pxp_default_cfg = {
.pxp_interrupt_init = _lv_gpu_nxp_pxp_interrupt_init, .pxp_interrupt_init = _lv_gpu_nxp_pxp_interrupt_init,
.pxp_interrupt_deinit = _lv_gpu_nxp_pxp_interrupt_deinit, .pxp_interrupt_deinit = _lv_gpu_nxp_pxp_interrupt_deinit,
.pxp_run = _lv_gpu_nxp_pxp_run .pxp_run = _lv_gpu_nxp_pxp_run,
.pxp_wait = _lv_gpu_nxp_pxp_wait,
}; };
/********************** /**********************
@@ -102,7 +107,7 @@ void PXP_IRQHandler(void)
if(kPXP_CompleteFlag & PXP_GetStatusFlags(LV_GPU_NXP_PXP_ID)) { if(kPXP_CompleteFlag & PXP_GetStatusFlags(LV_GPU_NXP_PXP_ID)) {
PXP_ClearStatusFlags(LV_GPU_NXP_PXP_ID, kPXP_CompleteFlag); PXP_ClearStatusFlags(LV_GPU_NXP_PXP_ID, kPXP_CompleteFlag);
#if defined(SDK_OS_FREE_RTOS) #if defined(SDK_OS_FREE_RTOS)
xSemaphoreGiveFromISR(s_pxpIdle, &taskAwake); xSemaphoreGiveFromISR(s_pxpIdleSem, &taskAwake);
portYIELD_FROM_ISR(taskAwake); portYIELD_FROM_ISR(taskAwake);
#else #else
s_pxpIdle = true; s_pxpIdle = true;
@@ -122,14 +127,13 @@ lv_nxp_pxp_cfg_t * lv_gpu_nxp_pxp_get_cfg(void)
static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void)
{ {
#if defined(SDK_OS_FREE_RTOS) #if defined(SDK_OS_FREE_RTOS)
s_pxpIdle = xSemaphoreCreateBinary(); s_pxpIdleSem = xSemaphoreCreateBinary();
if(s_pxpIdle == NULL) if(s_pxpIdleSem == NULL)
return LV_RES_INV; return LV_RES_INV;
NVIC_SetPriority(LV_GPU_NXP_PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1); NVIC_SetPriority(LV_GPU_NXP_PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
#else
s_pxpIdle = true;
#endif #endif
s_pxpIdle = true;
NVIC_EnableIRQ(LV_GPU_NXP_PXP_IRQ_ID); NVIC_EnableIRQ(LV_GPU_NXP_PXP_IRQ_ID);
@@ -140,21 +144,33 @@ static void _lv_gpu_nxp_pxp_interrupt_deinit(void)
{ {
NVIC_DisableIRQ(LV_GPU_NXP_PXP_IRQ_ID); NVIC_DisableIRQ(LV_GPU_NXP_PXP_IRQ_ID);
#if defined(SDK_OS_FREE_RTOS) #if defined(SDK_OS_FREE_RTOS)
vSemaphoreDelete(s_pxpIdle); vSemaphoreDelete(s_pxpIdleSem);
#endif #endif
} }
/**
* Function to start PXP job.
*/
static void _lv_gpu_nxp_pxp_run(void) static void _lv_gpu_nxp_pxp_run(void)
{ {
#if !defined(SDK_OS_FREE_RTOS)
s_pxpIdle = false; s_pxpIdle = false;
#endif
PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable);
PXP_Start(LV_GPU_NXP_PXP_ID); PXP_Start(LV_GPU_NXP_PXP_ID);
}
/**
* Function to wait for PXP completion.
*/
static void _lv_gpu_nxp_pxp_wait(void)
{
#if defined(SDK_OS_FREE_RTOS) #if defined(SDK_OS_FREE_RTOS)
PXP_COND_STOP(!xSemaphoreTake(s_pxpIdle, portMAX_DELAY), "xSemaphoreTake failed."); /* Return if PXP was never started, otherwise the semaphore will lock forever. */
if(s_pxpIdle == true)
return;
if(xSemaphoreTake(s_pxpIdleSem, portMAX_DELAY) == pdTRUE)
s_pxpIdle = true;
#else #else
while(s_pxpIdle == false) { while(s_pxpIdle == false) {
} }

View File

@@ -0,0 +1,502 @@
/**
* @file lv_draw_vglite.c
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite.h"
#if LV_USE_GPU_NXP_VG_LITE
#include <math.h>
#include "lv_draw_vglite_blend.h"
#include "lv_draw_vglite_line.h"
#include "lv_draw_vglite_rect.h"
#include "lv_draw_vglite_arc.h"
#include "lv_vglite_buf.h"
/*********************
* DEFINES
*********************/
/* Minimum area (in pixels) for VG-Lite blit/fill processing. */
#ifndef LV_GPU_NXP_VG_LITE_SIZE_LIMIT
#define LV_GPU_NXP_VG_LITE_SIZE_LIMIT 5000
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx);
static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx);
static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf);
static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
const lv_point_t * point2);
static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
const lv_area_t * coords);
static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
const lv_area_t * coords);
static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vglite_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_init_ctx(drv, draw_ctx);
lv_draw_vglite_ctx_t * vglite_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
vglite_draw_ctx->blend = lv_draw_vglite_blend;
vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
}
void lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
{
lv_draw_sw_deinit_ctx(drv, draw_ctx);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* During rendering, LVGL might initializes new draw_ctxs and start drawing into
* a separate buffer (called layer). If the content to be rendered has "holes",
* e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag.
* It means the renderers should draw into an ARGB buffer.
* With 32 bit color depth it's not a big problem but with 16 bit color depth
* the target pixel format is ARGB8565 which is not supported by the GPU.
* In this case, the VG-Lite callbacks should fallback to SW rendering.
*/
static inline bool need_argb8565_support(lv_draw_ctx_t * draw_ctx)
{
#if LV_COLOR_DEPTH != 32
if(draw_ctx->render_with_alpha)
return true;
#endif
return false;
}
static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx)
{
lv_gpu_nxp_vglite_init_buf(draw_ctx->buf, draw_ctx->buf_area, lv_area_get_width(draw_ctx->buf_area));
}
static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx)
{
vg_lite_finish();
lv_draw_sw_wait_for_finish(draw_ctx);
}
static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_blend_basic(draw_ctx, dsc);
return;
}
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to draw and the clip area*/
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
bool done = false;
/*Fill/Blend only non masked, normal blended*/
if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL &&
lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) {
const lv_color_t * src_buf = dsc->src_buf;
if(src_buf == NULL) {
done = (lv_gpu_nxp_vglite_fill(&blend_area, dsc->color, dsc->opa) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback.");
}
else {
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1);
src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1);
src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1;
src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1;
lv_coord_t src_stride = lv_area_get_width(dsc->blend_area);
done = (lv_gpu_nxp_vglite_blit(dest_buf, &blend_area, dest_stride,
src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback.");
}
}
if(!done)
lv_draw_sw_blend_basic(draw_ctx, dsc);
}
static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf)
{
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
const lv_color_t * src_buf = (const lv_color_t *)map_p;
if(!src_buf) {
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
return;
}
lv_area_t blend_area;
/*Let's get the blend area which is the intersection of the area to draw and the clip area*/
if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area))
return; /*Fully clipped, nothing to do*/
/*Make the blend area relative to the buffer*/
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
bool has_mask = lv_draw_mask_is_any(&blend_area);
bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
bool done = false;
if(!has_mask && !has_recolor && !lv_img_cf_is_chroma_keyed(cf) &&
lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT
#if LV_COLOR_DEPTH != 32
&& !lv_img_cf_has_alpha(cf)
#endif
) {
lv_color_t * dest_buf = draw_ctx->buf;
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
lv_area_t src_area;
src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1);
src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1);
src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1;
src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1;
lv_coord_t src_stride = lv_area_get_width(coords);
done = (lv_gpu_nxp_vglite_blit_transform(dest_buf, &blend_area, dest_stride,
src_buf, &src_area, src_stride, dsc) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback.");
}
if(!done)
lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
}
static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
const lv_point_t * point2)
{
if(dsc->width == 0)
return;
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(point1->x == point2->x && point1->y == point2->y)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_line(draw_ctx, dsc, point1, point2);
return;
}
lv_area_t rel_clip_area;
rel_clip_area.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2;
rel_clip_area.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2;
rel_clip_area.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2;
rel_clip_area.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2;
bool is_common;
is_common = _lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_ctx->clip_area);
if(!is_common)
return;
/* Make coordinates relative to the draw buffer */
lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_point_t rel_point1 = { point1->x - draw_ctx->buf_area->x1, point1->y - draw_ctx->buf_area->y1 };
lv_point_t rel_point2 = { point2->x - draw_ctx->buf_area->x1, point2->y - draw_ctx->buf_area->y1 };
bool done = false;
bool mask_any = lv_draw_mask_is_any(&rel_clip_area);
if(!mask_any) {
done = (lv_gpu_nxp_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite draw line failed. Fallback.");
}
if(!done)
lv_draw_sw_line(draw_ctx, dsc, point1, point2);
}
static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_rect(draw_ctx, dsc, coords);
return;
}
lv_draw_rect_dsc_t vglite_dsc;
lv_memcpy(&vglite_dsc, dsc, sizeof(vglite_dsc));
vglite_dsc.bg_opa = 0;
vglite_dsc.bg_img_opa = 0;
vglite_dsc.border_opa = 0;
vglite_dsc.outline_opa = 0;
#if LV_USE_DRAW_MASKS
/* Draw the shadow with CPU */
lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
vglite_dsc.shadow_opa = 0;
#endif /*LV_USE_DRAW_MASKS*/
/* Draw the background */
vglite_dsc.bg_opa = dsc->bg_opa;
if(lv_draw_vglite_bg(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
vglite_dsc.bg_opa = 0;
/* Draw the background image
* It will be done once draw_ctx->draw_img_decoded()
* callback gets called from lv_draw_sw_rect().
*/
vglite_dsc.bg_img_opa = dsc->bg_img_opa;
lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
vglite_dsc.bg_img_opa = 0;
/* Draw the border */
vglite_dsc.border_opa = dsc->border_opa;
if(lv_draw_vglite_border(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
vglite_dsc.border_opa = 0;
/* Draw the outline */
vglite_dsc.outline_opa = dsc->outline_opa;
if(lv_draw_vglite_outline(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
}
static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
{
if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN)
return LV_RES_INV;
lv_area_t rel_coords;
lv_area_copy(&rel_coords, coords);
/*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) {
rel_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
rel_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
rel_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
rel_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
}
/* Make coordinates relative to draw buffer */
lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_area_t clipped_coords;
if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
return LV_RES_INV;
bool mask_any = lv_draw_mask_is_any(&rel_coords);
lv_grad_dir_t grad_dir = dsc->bg_grad.dir;
lv_color_t bg_color = (grad_dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) ?
dsc->bg_color : dsc->bg_grad.stops[0].color;
if(bg_color.full == dsc->bg_grad.stops[1].color.full)
grad_dir = LV_GRAD_DIR_NONE;
/*
* Most simple case: just a plain rectangle (no mask, no radius, no gradient)
* shall be handled by draw_ctx->blend().
*
* Complex case: gradient or radius but no mask.
*/
if(!mask_any && ((dsc->radius != 0) || (grad_dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))) {
lv_res_t res = lv_gpu_nxp_vglite_draw_bg(&rel_coords, &rel_clip_area, dsc);
if(res != LV_RES_OK)
VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback.");
return res;
}
return LV_RES_INV;
}
static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->border_opa <= (lv_opa_t)LV_OPA_MIN)
return LV_RES_INV;
if(dsc->border_width == 0)
return LV_RES_INV;
if(dsc->border_post)
return LV_RES_INV;
if(dsc->border_side != (lv_border_side_t)LV_BORDER_SIDE_FULL)
return LV_RES_INV;
lv_area_t rel_coords;
lv_coord_t border_width = dsc->border_width;
/* Move border inwards to align with software rendered border */
rel_coords.x1 = coords->x1 + ceil(border_width / 2.0f);
rel_coords.x2 = coords->x2 - floor(border_width / 2.0f);
rel_coords.y1 = coords->y1 + ceil(border_width / 2.0f);
rel_coords.y2 = coords->y2 - floor(border_width / 2.0f);
/* Make coordinates relative to the draw buffer */
lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, true);
if(res != LV_RES_OK)
VG_LITE_LOG_TRACE("VG-Lite draw border failed. Fallback.");
return res;
}
static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->outline_opa <= (lv_opa_t)LV_OPA_MIN)
return LV_RES_INV;
if(dsc->outline_width == 0)
return LV_RES_INV;
/* Move outline outwards to align with software rendered outline */
lv_coord_t outline_pad = dsc->outline_pad - 1;
lv_area_t rel_coords;
rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f);
rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f);
rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f);
rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f);
/* Make coordinates relative to the draw buffer */
lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, false);
if(res != LV_RES_OK)
VG_LITE_LOG_TRACE("VG-Lite draw outline failed. Fallback.");
return res;
}
static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle)
{
bool done = false;
#if LV_USE_DRAW_MASKS
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
if(start_angle == end_angle)
return;
if(need_argb8565_support(draw_ctx)) {
lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
return;
}
/* Make coordinates relative to the draw buffer */
lv_point_t rel_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1};
lv_area_t rel_clip_area;
lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
done = (lv_gpu_nxp_vglite_draw_arc(&rel_center, (int32_t)radius, (int32_t)start_angle, (int32_t)end_angle,
&rel_clip_area, dsc) == LV_RES_OK);
if(!done)
VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback.");
#endif/*LV_USE_DRAW_MASKS*/
if(!done)
lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
}
#endif /*LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -0,0 +1,72 @@
/**
* @file lv_draw_vglite.h
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef LV_DRAW_VGLITE_H
#define LV_DRAW_VGLITE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "../../sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_draw_sw_ctx_t lv_draw_vglite_ctx_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_vglite_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx);
void lv_draw_vglite_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_NXP_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_VGLITE_H*/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2021, 2022 NXP * Copyright 2021-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -34,7 +34,8 @@
#include "lv_draw_vglite_arc.h" #include "lv_draw_vglite_arc.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "math.h" #include "lv_vglite_buf.h"
#include <math.h>
/********************* /*********************
* DEFINES * DEFINES
@@ -88,7 +89,7 @@ typedef struct _cubic_cont_pt {
static void rotate_point(int32_t angle, int32_t * x, int32_t * y); static void rotate_point(int32_t angle, int32_t * x, int32_t * y);
static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius,
int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw); int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@@ -102,31 +103,20 @@ static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius,
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle,
int32_t radius, int32_t start_angle, int32_t end_angle) const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc)
{ {
vg_lite_buffer_t vgbuf;
vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_error_t err = VG_LITE_SUCCESS;
lv_color32_t col32 = {.full = lv_color_to32(dsc->color)}; /*Convert color to RGBA8888*/ lv_color32_t col32 = {.full = lv_color_to32(dsc->color)}; /*Convert color to RGBA8888*/
lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area);
lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area);
vg_lite_path_t path; vg_lite_path_t path;
vg_lite_color_t vgcol; /* vglite takes ABGR */ vg_lite_color_t vgcol; /* vglite takes ABGR */
vg_lite_matrix_t matrix;
lv_opa_t opa = dsc->opa;
bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false; bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false;
lv_point_t clip_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1}; vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
/* path: max size = 16 cubic bezier (7 words each) */ /* path: max size = 16 cubic bezier (7 words each) */
int32_t arc_path[16 * 7]; int32_t arc_path[16 * 7];
lv_memzero(arc_path, sizeof(arc_path)); lv_memzero(arc_path, sizeof(arc_path));
/*** Init destination buffer ***/
if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t),
(const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK)
VG_LITE_RETURN_INV("Init buffer failed.");
/*** Init path ***/ /*** Init path ***/
lv_coord_t width = dsc->width; /* inner arc radius = outer arc radius - width */ lv_coord_t width = dsc->width; /* inner arc radius = outer arc radius - width */
if(width > (lv_coord_t)radius) if(width > (lv_coord_t)radius)
@@ -140,11 +130,11 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_MOVE; arc_path[pidx++] = VLC_OP_MOVE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
/* draw 1-5 outer quarters */ /* draw 1-5 outer quarters */
add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, clip_center, true); add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, center, true);
if(donut) { if(donut) {
/* close outer circle */ /* close outer circle */
@@ -152,24 +142,24 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE; arc_path[pidx++] = VLC_OP_LINE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
/* start inner circle */ /* start inner circle */
cp_x = radius - width; cp_x = radius - width;
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_MOVE; arc_path[pidx++] = VLC_OP_MOVE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
} }
else if(dsc->rounded != 0U) { /* 1st rounded arc ending */ else if(dsc->rounded != 0U) { /* 1st rounded arc ending */
cp_x = radius - width / 2; cp_x = radius - width / 2;
cp_y = 0; cp_y = 0;
rotate_point(end_angle, &cp_x, &cp_y); rotate_point(end_angle, &cp_x, &cp_y);
lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180), add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180),
round_center, true); &round_center, true);
} }
else { /* 1st flat ending */ else { /* 1st flat ending */
@@ -177,12 +167,12 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_
cp_y = 0; cp_y = 0;
rotate_point(end_angle, &cp_x, &cp_y); rotate_point(end_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE; arc_path[pidx++] = VLC_OP_LINE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
} }
/* draw 1-5 inner quarters */ /* draw 1-5 inner quarters */
add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, clip_center, false); add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, center, false);
/* last control point of curve */ /* last control point of curve */
if(donut) { /* close the loop */ if(donut) { /* close the loop */
@@ -190,17 +180,17 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE; arc_path[pidx++] = VLC_OP_LINE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
} }
else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */ else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */
cp_x = radius - width / 2; cp_x = radius - width / 2;
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360), add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360),
round_center, true); &round_center, true);
} }
else { /* 2nd flat ending */ else { /* 2nd flat ending */
@@ -208,46 +198,30 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_
cp_y = 0; cp_y = 0;
rotate_point(start_angle, &cp_x, &cp_y); rotate_point(start_angle, &cp_x, &cp_y);
arc_path[pidx++] = VLC_OP_LINE; arc_path[pidx++] = VLC_OP_LINE;
arc_path[pidx++] = clip_center.x + cp_x; arc_path[pidx++] = center->x + cp_x;
arc_path[pidx++] = clip_center.y + cp_y; arc_path[pidx++] = center->y + cp_y;
} }
arc_path[pidx++] = VLC_OP_END; 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, err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path,
(vg_lite_float_t) draw_ctx->clip_area->x1, (vg_lite_float_t) draw_ctx->clip_area->y1, (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t) draw_ctx->clip_area->x2) + 1.0f, ((vg_lite_float_t) draw_ctx->clip_area->y2) + 1.0f); ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
VG_LITE_ERR_RETURN_INV(err, "Init path failed."); VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
/* set rotation angle */ vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK)
VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix); vg_lite_identity(&matrix);
if(opa <= (lv_opa_t)LV_OPA_MAX) {
/* Only pre-multiply color if hardware pre-multiplication is not present */
if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8);
col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8);
col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8);
}
col32.ch.alpha = opa;
}
#if LV_COLOR_DEPTH==16
vgcol = col32.full;
#else /*LV_COLOR_DEPTH==32*/
vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) |
(uint32_t)col32.ch.red;
#endif
/*Clean & invalidate cache*/
lv_vglite_invalidate_cache();
/*** Draw arc ***/ /*** Draw arc ***/
err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Draw arc failed."); VG_LITE_ERR_RETURN_INV(err, "Draw arc failed.");
err = vg_lite_finish(); if(lv_vglite_run() != LV_RES_OK)
VG_LITE_ERR_RETURN_INV(err, "Finish failed."); VG_LITE_RETURN_INV("Run failed.");
err = vg_lite_clear_path(&path); err = vg_lite_clear_path(&path);
VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
@@ -564,50 +538,50 @@ static void get_arc_control_points(vg_arc * arc, bool start)
* center: (in) the center of the circle in draw coordinates * center: (in) the center of the circle in draw coordinates
* cw: (in) true if arc is clockwise * cw: (in) true if arc is clockwise
*/ */
static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, lv_point_t center, bool cw) static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, const lv_point_t * center, bool cw)
{ {
/* assumes first control point already in array arc_path[] */ /* assumes first control point already in array arc_path[] */
int idx = *pidx; int idx = *pidx;
if(cw) { if(cw) {
#if BEZIER_DBG_CONTROL_POINTS #if BEZIER_DBG_CONTROL_POINTS
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p1x + center.x; arc_path[idx++] = q_arc->p1x + center->x;
arc_path[idx++] = q_arc->p1y + center.y; arc_path[idx++] = q_arc->p1y + center->y;
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p2x + center.x; arc_path[idx++] = q_arc->p2x + center->x;
arc_path[idx++] = q_arc->p2y + center.y; arc_path[idx++] = q_arc->p2y + center->y;
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p3x + center.x; arc_path[idx++] = q_arc->p3x + center->x;
arc_path[idx++] = q_arc->p3y + center.y; arc_path[idx++] = q_arc->p3y + center->y;
#else #else
arc_path[idx++] = VLC_OP_CUBIC; arc_path[idx++] = VLC_OP_CUBIC;
arc_path[idx++] = q_arc->p1x + center.x; arc_path[idx++] = q_arc->p1x + center->x;
arc_path[idx++] = q_arc->p1y + center.y; arc_path[idx++] = q_arc->p1y + center->y;
arc_path[idx++] = q_arc->p2x + center.x; arc_path[idx++] = q_arc->p2x + center->x;
arc_path[idx++] = q_arc->p2y + center.y; arc_path[idx++] = q_arc->p2y + center->y;
arc_path[idx++] = q_arc->p3x + center.x; arc_path[idx++] = q_arc->p3x + center->x;
arc_path[idx++] = q_arc->p3y + center.y; arc_path[idx++] = q_arc->p3y + center->y;
#endif #endif
} }
else { /* reverse points order when counter-clockwise */ else { /* reverse points order when counter-clockwise */
#if BEZIER_DBG_CONTROL_POINTS #if BEZIER_DBG_CONTROL_POINTS
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p2x + center.x; arc_path[idx++] = q_arc->p2x + center->x;
arc_path[idx++] = q_arc->p2y + center.y; arc_path[idx++] = q_arc->p2y + center->y;
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p1x + center.x; arc_path[idx++] = q_arc->p1x + center->x;
arc_path[idx++] = q_arc->p1y + center.y; arc_path[idx++] = q_arc->p1y + center->y;
arc_path[idx++] = VLC_OP_LINE; arc_path[idx++] = VLC_OP_LINE;
arc_path[idx++] = q_arc->p0x + center.x; arc_path[idx++] = q_arc->p0x + center->x;
arc_path[idx++] = q_arc->p0y + center.y; arc_path[idx++] = q_arc->p0y + center->y;
#else #else
arc_path[idx++] = VLC_OP_CUBIC; arc_path[idx++] = VLC_OP_CUBIC;
arc_path[idx++] = q_arc->p2x + center.x; arc_path[idx++] = q_arc->p2x + center->x;
arc_path[idx++] = q_arc->p2y + center.y; arc_path[idx++] = q_arc->p2y + center->y;
arc_path[idx++] = q_arc->p1x + center.x; arc_path[idx++] = q_arc->p1x + center->x;
arc_path[idx++] = q_arc->p1y + center.y; arc_path[idx++] = q_arc->p1y + center->y;
arc_path[idx++] = q_arc->p0x + center.x; arc_path[idx++] = q_arc->p0x + center->x;
arc_path[idx++] = q_arc->p0y + center.y; arc_path[idx++] = q_arc->p0y + center->y;
#endif #endif
} }
/* update index i n path array*/ /* update index i n path array*/
@@ -615,7 +589,7 @@ static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, l
} }
static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius,
int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw) int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw)
{ {
/* set number of arcs to draw */ /* set number of arcs to draw */
vg_arc q_arc; vg_arc q_arc;

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2021, 2022 NXP * Copyright 2021-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -40,7 +40,7 @@ extern "C" {
#include "../../../lv_conf_internal.h" #include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "lv_gpu_nxp_vglite.h" #include "lv_vglite_utils.h"
/********************* /*********************
* DEFINES * DEFINES
@@ -54,17 +54,21 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
/*** /**
* Draw arc shape with effects * Draw arc shape with effects
* @param draw_ctx drawing context *
* @param dsc the arc description structure (width, rounded ending, opacity) * @param[in] center Arc center with relative coordinates
* @param center the coordinates of the arc center * @param[in] radius Radius of external arc
* @param radius the radius of external arc * @param[in] start_angle Starting angle in degrees
* @param start_angle the starting angle in degrees * @param[in] end_angle Ending angle in degrees
* @param end_angle the ending angle in degrees * @param[in] clip_area Clipping area with relative coordinates to dest buff
* @param[in] dsc Arc description structure (width, rounded ending, opacity)
*
* @retval LV_RES_OK Draw completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle,
int32_t radius, int32_t start_angle, int32_t end_angle); const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc);
/********************** /**********************
* MACROS * MACROS

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -34,12 +34,19 @@
#include "lv_draw_vglite_blend.h" #include "lv_draw_vglite_blend.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "lv_vglite_buf.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
/* Enable BLIT quality degradation workaround for RT595, recommended for screen's dimension > 352 pixels */ /** Stride in px required by VG-Lite HW*/
#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U
/**
* Enable BLIT quality degradation workaround for RT595,
* recommended for screen's dimension > 352 pixels.
*/
#define RT595_BLIT_WRKRND_ENABLED 1 #define RT595_BLIT_WRKRND_ENABLED 1
/* Internal compound symbol */ /* Internal compound symbol */
@@ -51,12 +58,13 @@
#define VG_LITE_BLIT_SPLIT_ENABLED 0 #define VG_LITE_BLIT_SPLIT_ENABLED 0
#endif #endif
/** #if VG_LITE_BLIT_SPLIT_ENABLED
* BLIT split threshold - BLITs with width or height higher than this value will be done /**
* in multiple steps. Value must be 16-aligned. Don't change. * BLIT split threshold - BLITs with width or height higher than this value will be done
*/ * in multiple steps. Value must be 16-aligned. Don't change.
#define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 */
#define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352
#endif
/********************** /**********************
* TYPEDEFS * TYPEDEFS
@@ -67,63 +75,87 @@
**********************/ **********************/
/** /**
* BLock Image Transfer - single direct BLIT. * Blit single image, with optional opacity.
*
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] src_area Source area with relative coordinates of source buffer
* @param[in] opa Opacity
* *
* @param[in] blit Description of the transfer
* @retval LV_RES_OK Transfer complete * @retval LV_RES_OK Transfer complete
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit); static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa);
/**
* Check source memory and stride alignment.
*
* @param[in] src_buf Source buffer
* @param[in] src_stride Stride of source buffer in pixels
*
* @retval LV_RES_OK Alignment OK
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/
static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride);
/**
* Creates matrix that translates to origin of given destination area.
*
* @param[in] dest_area Area with relative coordinates of destination buffer
*/
static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area);
/**
* Creates matrix that translates to origin of given destination area with transformation (scale or rotate).
*
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dsc Image descriptor
*/
static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc);
#if VG_LITE_BLIT_SPLIT_ENABLED #if VG_LITE_BLIT_SPLIT_ENABLED
/** /**
* Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only.
* *
* @param[in,out] area Area to be updated * @param[in/out] area Area to be updated
* @param[in,out] buf Pointer to be updated * @param[in/out] buf Pointer to be updated
*/ */
static void _align_x(lv_area_t * area, lv_color_t ** buf); static void align_x(lv_area_t * area, lv_color_t ** buf);
/** /**
* Move buffer pointer to the area start and update variables, Y-axis only. * Move buffer pointer to the area start and update variables, Y-axis only.
* *
* @param[in,out] area Area to be updated * @param[in/out] area Area to be updated
* @param[in,out] buf Pointer to be updated * @param[in/out] buf Pointer to be updated
* @param[in] stridePx Buffer stride in pixels * @param[in] stride Buffer stride in pixels
*/ */
static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx); static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride);
/** /**
* Software BLIT as a fall-back scenario. * Blit image split in tiles, with optional opacity.
* *
* @param[in] blit BLIT configuration * @param[in/out] dest_buf Destination buffer
*/ * @param[in] dest_area Area with relative coordinates of destination buffer
static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit); * @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf Source buffer
/** * @param[in] src_area Source area with relative coordinates of source buffer
* Verify BLIT structure - widths, stride, pointer alignment * @param[in] src_stride Stride of source buffer in pixels
* * @param[in] opa Opacity
* @param[in] blit BLIT configuration *
* @retval LV_RES_OK * @retval LV_RES_OK Transfer complete
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit); static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
/** lv_opa_t opa);
* BLock Image Transfer - split BLIT.
*
* @param[in] blit BLIT configuration
* @retval LV_RES_OK Transfer complete
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/
static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit);
#endif #endif
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
**********************/ **********************/
static vg_lite_matrix_t vgmatrix;
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
@@ -132,98 +164,57 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa)
const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)
{ {
uint32_t area_size = lv_area_get_size(fill_area);
lv_coord_t area_w = lv_area_get_width(fill_area);
lv_coord_t area_h = lv_area_get_height(fill_area);
if(opa >= (lv_opa_t)LV_OPA_MAX) {
if(area_size < LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT)
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT);
}
else {
if(area_size < LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT)
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT);
}
vg_lite_buffer_t vgbuf;
vg_lite_rectangle_t rect;
vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_error_t err = VG_LITE_SUCCESS;
lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/ lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/
vg_lite_color_t vgcol; /* vglite takes ABGR */ vg_lite_color_t vgcol; /* vglite takes ABGR */
vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
(const lv_color_t *)dest_buf, false) != LV_RES_OK) if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK)
VG_LITE_RETURN_INV("Init buffer failed."); VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
if(opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/ if(opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/
rect.x = fill_area->x1; vg_lite_rectangle_t rect = {
rect.y = fill_area->y1; .x = dest_area->x1,
rect.width = area_w; .y = dest_area->y1,
rect.height = area_h; .width = lv_area_get_width(dest_area),
.height = lv_area_get_height(dest_area)
};
/*Clean & invalidate cache*/ err = vg_lite_clear(vgbuf, &rect, vgcol);
lv_vglite_invalidate_cache();
#if LV_COLOR_DEPTH==16
vgcol = col32.full;
#else /*LV_COLOR_DEPTH==32*/
vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) |
(uint32_t)col32.ch.red;
#endif
err = vg_lite_clear(&vgbuf, &rect, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Clear failed."); VG_LITE_ERR_RETURN_INV(err, "Clear failed.");
err = vg_lite_finish(); if(lv_vglite_run() != LV_RES_OK)
VG_LITE_ERR_RETURN_INV(err, "Finish failed."); VG_LITE_RETURN_INV("Run failed.");
} }
else { /*fill with transparency*/ else { /*fill with transparency*/
vg_lite_path_t path; vg_lite_path_t path;
int32_t path_data[] = { /*VG rectangular path*/ int32_t path_data[] = { /*VG rectangular path*/
VLC_OP_MOVE, fill_area->x1, fill_area->y1, VLC_OP_MOVE, dest_area->x1, dest_area->y1,
VLC_OP_LINE, fill_area->x2 + 1, fill_area->y1, VLC_OP_LINE, dest_area->x2 + 1, dest_area->y1,
VLC_OP_LINE, fill_area->x2 + 1, fill_area->y2 + 1, VLC_OP_LINE, dest_area->x2 + 1, dest_area->y2 + 1,
VLC_OP_LINE, fill_area->x1, fill_area->y2 + 1, VLC_OP_LINE, dest_area->x1, dest_area->y2 + 1,
VLC_OP_LINE, fill_area->x1, fill_area->y1, VLC_OP_LINE, dest_area->x1, dest_area->y1,
VLC_OP_END VLC_OP_END
}; };
err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(path_data), path_data, err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(path_data), path_data,
(vg_lite_float_t) fill_area->x1, (vg_lite_float_t) fill_area->y1, (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1,
((vg_lite_float_t) fill_area->x2) + 1.0f, ((vg_lite_float_t) fill_area->y2) + 1.0f); ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f);
VG_LITE_ERR_RETURN_INV(err, "Init path failed."); VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
/* Only pre-multiply color if hardware pre-multiplication is not present */
if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8);
col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8);
col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8);
}
col32.ch.alpha = opa;
#if LV_COLOR_DEPTH==16
vgcol = col32.full;
#else /*LV_COLOR_DEPTH==32*/
vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) |
(uint32_t)col32.ch.red;
#endif
/*Clean & invalidate cache*/
lv_vglite_invalidate_cache();
vg_lite_matrix_t matrix; vg_lite_matrix_t matrix;
vg_lite_identity(&matrix); vg_lite_identity(&matrix);
/*Draw rectangle*/ /*Draw rectangle*/
err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Draw rectangle failed."); VG_LITE_ERR_RETURN_INV(err, "Draw rectangle failed.");
err = vg_lite_finish(); if(lv_vglite_run() != LV_RES_OK)
VG_LITE_ERR_RETURN_INV(err, "Finish failed."); VG_LITE_RETURN_INV("Run failed.");
err = vg_lite_clear_path(&path); err = vg_lite_clear_path(&path);
VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
@@ -232,41 +223,64 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv
return LV_RES_OK; return LV_RES_OK;
} }
lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
lv_opa_t opa)
{ {
uint32_t dest_size = lv_area_get_size(&blit->dst_area); /* Set vgmatrix. */
lv_vglite_set_translation_matrix(dest_area);
if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { /* Set src_vgbuf structure. */
if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) lv_vglite_set_src_buf(src_buf, src_area, src_stride);
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT);
}
else {
if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT)
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT);
}
#if VG_LITE_BLIT_SPLIT_ENABLED #if VG_LITE_BLIT_SPLIT_ENABLED
return _lv_gpu_nxp_vglite_blit_split(blit); lv_color_t * orig_dest_buf = dest_buf;
#endif /* non RT595 */
/* Just pass down */ lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, opa);
return _lv_gpu_nxp_vglite_blit_single(blit);
/* Restore the original dest_vgbuf memory address. */
lv_vglite_set_dest_buf_ptr(orig_dest_buf);
return rv;
#else
LV_UNUSED(dest_buf);
LV_UNUSED(dest_stride);
if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
VG_LITE_RETURN_INV("Check src alignment failed.");
return lv_vglite_blit_single(dest_area, src_area, opa);
#endif
} }
lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit) lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc)
{ {
uint32_t dest_size = lv_area_get_size(&blit->dst_area); /* Set vgmatrix. */
lv_vglite_set_transformation_matrix(dest_area, dsc);
if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { /* Set src_vgbuf structure. */
if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) lv_vglite_set_src_buf(src_buf, src_area, src_stride);
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT);
}
else {
if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT)
VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT);
}
return _lv_gpu_nxp_vglite_blit_single(blit); #if VG_LITE_BLIT_SPLIT_ENABLED
lv_color_t * orig_dest_buf = dest_buf;
lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc->opa);
/* Restore the original dest_vgbuf memory address. */
lv_vglite_set_dest_buf_ptr(orig_dest_buf);
return rv;
#else
LV_UNUSED(dest_buf);
LV_UNUSED(dest_stride);
if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
VG_LITE_RETURN_INV("Check src alignment failed.");
return lv_vglite_blit_single(dest_area, src_area, dsc->opa);
#endif
} }
/********************** /**********************
@@ -274,223 +288,196 @@ lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit)
**********************/ **********************/
#if VG_LITE_BLIT_SPLIT_ENABLED #if VG_LITE_BLIT_SPLIT_ENABLED
static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit) static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
lv_opa_t opa)
{ {
lv_res_t rv = LV_RES_INV; lv_res_t rv = LV_RES_INV;
if(_lv_gpu_nxp_vglite_check_blit(blit) != LV_RES_OK) { VG_LITE_LOG_TRACE("Blit "
PRINT_BLT("Blit check failed\n"); "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
return LV_RES_INV; "Size: ([%dx%d] -> [%dx%d]) | "
} "Addr: (0x%x -> 0x%x)",
src_area->x1, src_area->y1, src_area->x2, src_area->y2,
dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
lv_area_get_width(src_area), lv_area_get_height(src_area),
lv_area_get_width(dest_area), lv_area_get_height(dest_area),
(uintptr_t)src_buf, (uintptr_t)dest_buf);
PRINT_BLT("BLIT from: " /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */
"Area: %03d,%03d - %03d,%03d " align_x(src_area, (lv_color_t **)&src_buf);
"Addr: %d\n\n", align_y(src_area, (lv_color_t **)&src_buf, src_stride);
blit->src_area.x1, blit->src_area.y1, align_x(dest_area, (lv_color_t **)&dest_buf);
blit->src_area.x2, blit->src_area.y2, align_y(dest_area, (lv_color_t **)&dest_buf, dest_stride);
(uintptr_t) blit->src);
PRINT_BLT("BLIT to: "
"Area: %03d,%03d - %03d,%03d "
"Addr: %d\n\n",
blit->dst_area.x1, blit->dst_area.y1,
blit->dst_area.x2, blit->dst_area.y2,
(uintptr_t) blit->src);
/* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */
_align_x(&blit->src_area, (lv_color_t **)&blit->src);
_align_y(&blit->src_area, (lv_color_t **)&blit->src, blit->src_stride / sizeof(lv_color_t));
_align_x(&blit->dst_area, (lv_color_t **)&blit->dst);
_align_y(&blit->dst_area, (lv_color_t **)&blit->dst, blit->dst_stride / sizeof(lv_color_t));
/* Stage 2: If we're in limit, do a single BLIT */ /* Stage 2: If we're in limit, do a single BLIT */
if((blit->src_area.x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && if((src_area->x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) &&
(blit->src_area.y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { (src_area->y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) {
PRINT_BLT("Simple blit!\n"); if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
return _lv_gpu_nxp_vglite_blit_single(blit); VG_LITE_RETURN_INV("Check src alignment failed.");
/* Set new dest_vgbuf and src_vgbuf memory addresses. */
lv_vglite_set_dest_buf_ptr(dest_buf);
lv_vglite_set_src_buf_ptr(src_buf);
/* Set vgmatrix. */
lv_vglite_set_translation_matrix(dest_area);
rv = lv_vglite_blit_single(dest_area, src_area, opa);
VG_LITE_LOG_TRACE("Single "
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
"Size: ([%dx%d] -> [%dx%d]) | "
"Addr: (0x%x -> 0x%x) %s",
src_area->x1, src_area->y1, src_area->x2, src_area->y2,
dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
lv_area_get_width(src_area), lv_area_get_height(src_area),
lv_area_get_width(dest_area), lv_area_get_height(dest_area),
(uintptr_t)src_buf, (uintptr_t)dest_buf,
rv == LV_RES_OK ? "OK!" : "FAILED!");
return rv;
}; };
/* Stage 3: Split the BLIT into multiple tiles */ /* Stage 3: Split the BLIT into multiple tiles */
PRINT_BLT("Split blit!\n"); VG_LITE_LOG_TRACE("Split "
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
PRINT_BLT("Blit " "Size: ([%dx%d] -> [%dx%d]) | "
"([%03d,%03d], [%03d,%03d]) -> " "Addr: (0x%x -> 0x%x)",
"([%03d,%03d], [%03d,%03d]) | " src_area->x1, src_area->y1, src_area->x2, src_area->y2,
"([%03dx%03d] -> [%03dx%03d]) | " dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
"A:(%d -> %d)\n", lv_area_get_width(src_area), lv_area_get_height(src_area),
blit->src_area.x1, blit->src_area.y1, blit->src_area.x2, blit->src_area.y2, lv_area_get_width(dest_area), lv_area_get_height(dest_area),
blit->dst_area.x1, blit->dst_area.y1, blit->dst_area.x2, blit->dst_area.y2, (uintptr_t)src_buf, (uintptr_t)dest_buf);
lv_area_get_width(&blit->src_area), lv_area_get_height(&blit->src_area),
lv_area_get_width(&blit->dst_area), lv_area_get_height(&blit->dst_area),
(uintptr_t) blit->src, (uintptr_t) blit->dst);
lv_coord_t totalWidth = lv_area_get_width(&blit->src_area); lv_coord_t width = lv_area_get_width(src_area);
lv_coord_t totalHeight = lv_area_get_height(&blit->src_area); lv_coord_t height = lv_area_get_height(src_area);
lv_gpu_nxp_vglite_blit_info_t tileBlit;
/* Number of tiles needed */ /* Number of tiles needed */
int totalTilesX = (blit->src_area.x1 + totalWidth + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / int total_tiles_x = (src_area->x1 + width + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
int totalTilesY = (blit->src_area.y1 + totalHeight + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / int total_tiles_y = (src_area->y1 + height + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
/* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as
* the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be
* different */ * different */
int shiftSrcX = (blit->src_area.x1 > blit->dst_area.x1) ? (blit->src_area.x1 - blit->dst_area.x1) : 0; int shift_src_x = (src_area->x1 > dest_area->x1) ? (src_area->x1 - dest_area->x1) : 0;
int shiftDstX = (blit->src_area.x1 < blit->dst_area.x1) ? (blit->dst_area.x1 - blit->src_area.x1) : 0; int shift_dest_x = (src_area->x1 < dest_area->x1) ? (dest_area->x1 - src_area->x1) : 0;
PRINT_BLT("\n"); VG_LITE_LOG_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x);
PRINT_BLT("Align shift: src: %d, dst: %d\n", shiftSrcX, shiftDstX);
tileBlit = *blit; lv_color_t * tile_dest_buf;
lv_area_t tile_dest_area;
const lv_color_t * tile_src_buf;
lv_area_t tile_src_area;
for(int tileY = 0; tileY < totalTilesY; tileY++) { for(int y = 0; y < total_tiles_y; y++) {
tileBlit.src_area.y1 = 0; /* no vertical alignment, always start from 0 */ tile_src_area.y1 = 0; /* no vertical alignment, always start from 0 */
tileBlit.src_area.y2 = totalHeight - tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; tile_src_area.y2 = height - y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
if(tileBlit.src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { if(tile_src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
tileBlit.src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ tile_src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */
} }
tileBlit.src = blit->src + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->src_stride / sizeof( tile_src_buf = src_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * src_stride;
lv_color_t); /* stride in px! */
tileBlit.dst_area.y1 = tileBlit.src_area.y1; /* y has no alignment, always in sync with src */ tile_dest_area.y1 = tile_src_area.y1; /* y has no alignment, always in sync with src */
tileBlit.dst_area.y2 = tileBlit.src_area.y2; tile_dest_area.y2 = tile_src_area.y2;
tileBlit.dst = blit->dst + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->dst_stride / sizeof( tile_dest_buf = dest_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * dest_stride;
lv_color_t); /* stride in px! */
for(int tileX = 0; tileX < totalTilesX; tileX++) { for(int x = 0; x < total_tiles_x; x++) {
if(tileX == 0) { if(x == 0) {
/* 1st tile is special - there may be a gap between buffer start pointer /* 1st tile is special - there may be a gap between buffer start pointer
* and area.x1 value, as the pointer has to be aligned. * and area.x1 value, as the pointer has to be aligned.
* tileBlit.src pointer - keep init value from Y-loop. * tile_src_buf pointer - keep init value from Y-loop.
* Also, 1st tile start is not shifted! shift is applied from 2nd tile */ * Also, 1st tile start is not shifted! shift is applied from 2nd tile */
tileBlit.src_area.x1 = blit->src_area.x1; tile_src_area.x1 = src_area->x1;
tileBlit.dst_area.x1 = blit->dst_area.x1; tile_dest_area.x1 = dest_area->x1;
} }
else { else {
/* subsequent tiles always starts from 0, but shifted*/ /* subsequent tiles always starts from 0, but shifted*/
tileBlit.src_area.x1 = 0 + shiftSrcX; tile_src_area.x1 = 0 + shift_src_x;
tileBlit.dst_area.x1 = 0 + shiftDstX; tile_dest_area.x1 = 0 + shift_dest_x;
/* and advance start pointer + 1 tile size */ /* and advance start pointer + 1 tile size */
tileBlit.src += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; tile_src_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
tileBlit.dst += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; tile_dest_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
} }
/* Clip tile end coordinates */ /* Clip tile end coordinates */
tileBlit.src_area.x2 = totalWidth + blit->src_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; tile_src_area.x2 = width + src_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
if(tileBlit.src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { if(tile_src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
tileBlit.src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; tile_src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
} }
tileBlit.dst_area.x2 = totalWidth + blit->dst_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; tile_dest_area.x2 = width + dest_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
if(tileBlit.dst_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { if(tile_dest_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
tileBlit.dst_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; tile_dest_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
} }
if(tileX < (totalTilesX - 1)) { if(x < (total_tiles_x - 1)) {
/* And adjust end coords if shifted, but not for last tile! */ /* And adjust end coords if shifted, but not for last tile! */
tileBlit.src_area.x2 += shiftSrcX; tile_src_area.x2 += shift_src_x;
tileBlit.dst_area.x2 += shiftDstX; tile_dest_area.x2 += shift_dest_x;
} }
rv = _lv_gpu_nxp_vglite_blit_single(&tileBlit); if(check_src_alignment(tile_src_buf, src_stride) != LV_RES_OK)
VG_LITE_RETURN_INV("Check src alignment failed.");
#if BLIT_DBG_AREAS /* Set vgmatrix. */
lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.dst, tileBlit.dst_width, tileBlit.dst_height, &tileBlit.dst_area, lv_vglite_set_translation_matrix(&tile_dest_area);
LV_COLOR_RED);
lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.src, tileBlit.src_width, tileBlit.src_height, &tileBlit.src_area,
LV_COLOR_GREEN);
#endif
PRINT_BLT("Tile [%d, %d]: " /* Set new dest_vgbuf and src_vgbuf memory addresses. */
"([%d,%d], [%d,%d]) -> " lv_vglite_set_dest_buf_ptr(tile_dest_buf);
"([%d,%d], [%d,%d]) | " lv_vglite_set_src_buf_ptr(tile_src_buf);
"([%dx%d] -> [%dx%d]) | "
"A:(0x%8X -> 0x%8X) %s\n",
tileX, tileY,
tileBlit.src_area.x1, tileBlit.src_area.y1, tileBlit.src_area.x2, tileBlit.src_area.y2,
tileBlit.dst_area.x1, tileBlit.dst_area.y1, tileBlit.dst_area.x2, tileBlit.dst_area.y2,
lv_area_get_width(&tileBlit.src_area), lv_area_get_height(&tileBlit.src_area),
lv_area_get_width(&tileBlit.dst_area), lv_area_get_height(&tileBlit.dst_area),
(uintptr_t) tileBlit.src, (uintptr_t) tileBlit.dst,
rv == LV_RES_OK ? "OK!" : "!!! FAILED !!!");
if(rv != LV_RES_OK) { /* if anything goes wrong... */ rv = lv_vglite_blit_single(&tile_dest_area, &tile_src_area, opa);
#if LV_GPU_NXP_VG_LITE_LOG_ERRORS
LV_LOG_ERROR("Split blit failed. Trying SW blit instead."); VG_LITE_LOG_TRACE("Tile [%d, %d] "
#endif "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
_sw_blit(&tileBlit); "Size: ([%dx%d] -> [%dx%d]) | "
rv = LV_RES_OK; /* Don't report error, as SW BLIT was performed */ "Addr: (0x%x -> 0x%x) %s",
x, y,
tile_src_area.x1, tile_src_area.y1, tile_src_area.x2, tile_src_area.y2,
tile_dest_area.x1, tile_dest_area.y1, tile_dest_area.x2, tile_dest_area.y2,
lv_area_get_width(&tile_src_area), lv_area_get_height(&tile_src_area),
lv_area_get_width(&tile_dest_area), lv_area_get_height(&tile_dest_area),
(uintptr_t)tile_src_buf, (uintptr_t)tile_dest_buf,
rv == LV_RES_OK ? "OK!" : "FAILED!");
if(rv != LV_RES_OK) {
return rv;
} }
} }
PRINT_BLT(" \n");
} }
return rv; /* should never fail */ return rv;
} }
#endif /* VG_LITE_BLIT_SPLIT_ENABLED */ #endif /* VG_LITE_BLIT_SPLIT_ENABLED */
static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit) static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa)
{ {
vg_lite_buffer_t src_vgbuf, dst_vgbuf;
vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_error_t err = VG_LITE_SUCCESS;
uint32_t rect[4]; vg_lite_buffer_t * dst_vgbuf = lv_vglite_get_dest_buf();
vg_lite_float_t scale = 1.0; vg_lite_buffer_t * src_vgbuf = lv_vglite_get_src_buf();
if(blit == NULL) { uint32_t rect[] = {
/*Wrong parameter*/ (uint32_t)src_area->x1, /* start x */
return LV_RES_INV; (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 */
if(blit->opa < (lv_opa_t) LV_OPA_MIN) { };
return LV_RES_OK; /*Nothing to BLIT*/
}
/*Wrap src/dst buffer into VG-Lite buffer*/
if(lv_vglite_init_buf(&src_vgbuf, (uint32_t)blit->src_width, (uint32_t)blit->src_height, (uint32_t)blit->src_stride,
blit->src, true) != LV_RES_OK)
VG_LITE_RETURN_INV("Init buffer failed.");
if(lv_vglite_init_buf(&dst_vgbuf, (uint32_t)blit->dst_width, (uint32_t)blit->dst_height, (uint32_t)blit->dst_stride,
blit->dst, false) != LV_RES_OK)
VG_LITE_RETURN_INV("Init buffer failed.");
rect[0] = (uint32_t)blit->src_area.x1; /* start x */
rect[1] = (uint32_t)blit->src_area.y1; /* start y */
rect[2] = (uint32_t)blit->src_area.x2 - (uint32_t)blit->src_area.x1 + 1U; /* width */
rect[3] = (uint32_t)blit->src_area.y2 - (uint32_t)blit->src_area.y1 + 1U; /* height */
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
vg_lite_translate((vg_lite_float_t)blit->dst_area.x1, (vg_lite_float_t)blit->dst_area.y1, &matrix);
if((blit->angle != 0) || (blit->zoom != LV_IMG_ZOOM_NONE)) {
vg_lite_translate(blit->pivot.x, blit->pivot.y, &matrix);
vg_lite_rotate(blit->angle / 10.0f, &matrix); /* angle is 1/10 degree */
scale = 1.0f * blit->zoom / LV_IMG_ZOOM_NONE;
vg_lite_scale(scale, scale, &matrix);
vg_lite_translate(0.0f - blit->pivot.x, 0.0f - blit->pivot.y, &matrix);
}
/*Clean & invalidate cache*/
lv_vglite_invalidate_cache();
uint32_t color; uint32_t color;
vg_lite_blend_t blend; vg_lite_blend_t blend;
if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { if(opa >= (lv_opa_t)LV_OPA_MAX) {
color = 0xFFFFFFFFU; color = 0xFFFFFFFFU;
blend = VG_LITE_BLEND_SRC_OVER; blend = VG_LITE_BLEND_SRC_OVER;
src_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT; src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
} }
else { else {
uint32_t opa = (uint32_t)blit->opa;
if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
color = (opa << 24) | 0x00FFFFFFU; color = (opa << 24) | 0x00FFFFFFU;
} }
@@ -498,94 +485,83 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b
color = (opa << 24) | (opa << 16) | (opa << 8) | opa; color = (opa << 24) | (opa << 16) | (opa << 8) | opa;
} }
blend = VG_LITE_BLEND_SRC_OVER; blend = VG_LITE_BLEND_SRC_OVER;
src_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
src_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT; src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
} }
err = vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT); bool scissoring = lv_area_get_width(dest_area) < lv_area_get_width(src_area) ||
VG_LITE_ERR_RETURN_INV(err, "Blit rectangle failed."); lv_area_get_height(dest_area) < lv_area_get_height(src_area);
if(scissoring) {
vg_lite_enable_scissor();
vg_lite_set_scissor((int32_t)dest_area->x1, (int32_t)dest_area->y1,
(int32_t)lv_area_get_width(dest_area),
(int32_t)lv_area_get_height(dest_area));
}
err = vg_lite_finish(); err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, &vgmatrix, blend, color, VG_LITE_FILTER_POINT);
VG_LITE_ERR_RETURN_INV(err, "Finish failed."); if(err != VG_LITE_SUCCESS) {
if(scissoring)
vg_lite_disable_scissor();
VG_LITE_RETURN_INV("Blit rectangle failed.");
}
if(lv_vglite_run() != LV_RES_OK) {
if(scissoring)
vg_lite_disable_scissor();
VG_LITE_RETURN_INV("Run failed.");
}
if(scissoring)
vg_lite_disable_scissor();
return LV_RES_OK; return LV_RES_OK;
} }
static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride)
{
/* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */
/* Test for pointer alignment */
if((((uintptr_t)src_buf) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U)
VG_LITE_RETURN_INV("Src buffer ptr (0x%x) not aligned to 0x%x bytes.",
(size_t)src_buf, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
/* Test for stride alignment */
if((src_stride % (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0x0U)
VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.",
src_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
return LV_RES_OK;
}
static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area)
{
vg_lite_identity(&vgmatrix);
vg_lite_translate((vg_lite_float_t)dest_area->x1, (vg_lite_float_t)dest_area->y1, &vgmatrix);
}
static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc)
{
lv_vglite_set_translation_matrix(dest_area);
bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE);
bool has_rotation = (dsc->angle != 0);
if(has_scale || has_rotation) {
vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &vgmatrix);
if(has_rotation)
vg_lite_rotate(dsc->angle / 10.0f, &vgmatrix); /* angle is 1/10 degree */
if(has_scale) {
vg_lite_float_t scale = 1.0f * dsc->zoom / LV_IMG_ZOOM_NONE;
vg_lite_scale(scale, scale, &vgmatrix);
}
vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &vgmatrix);
}
}
#if VG_LITE_BLIT_SPLIT_ENABLED #if VG_LITE_BLIT_SPLIT_ENABLED
static void align_x(lv_area_t * area, lv_color_t ** buf)
static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit)
{ {
int x, y; int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE / sizeof(lv_color_t)));
lv_coord_t w = lv_area_get_width(&blit->src_area);
lv_coord_t h = lv_area_get_height(&blit->src_area);
int32_t srcStridePx = blit->src_stride / (int32_t)sizeof(lv_color_t);
int32_t dstStridePx = blit->dst_stride / (int32_t)sizeof(lv_color_t);
lv_color_t * src = (lv_color_t *)blit->src + blit->src_area.y1 * srcStridePx + blit->src_area.x1;
lv_color_t * dst = (lv_color_t *)blit->dst + blit->dst_area.y1 * dstStridePx + blit->dst_area.x1;
if(blit->opa >= (lv_opa_t)LV_OPA_MAX) {
/* simple copy */
for(y = 0; y < h; y++) {
lv_memcpy(dst, src, (uint32_t)w * sizeof(lv_color_t));
src += srcStridePx;
dst += dstStridePx;
}
}
else if(blit->opa >= LV_OPA_MIN) {
/* alpha blending */
for(y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
dst[x] = lv_color_mix(src[x], dst[x], blit->opa);
}
src += srcStridePx;
dst += dstStridePx;
}
}
}
static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit)
{
/* Test for minimal width */
if(lv_area_get_width(&blit->src_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX)
VG_LITE_RETURN_INV("Src area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->src_area),
LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
/* Test for minimal width */
if(lv_area_get_width(&blit->dst_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX)
VG_LITE_RETURN_INV("Dest area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->dst_area),
LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
/* Test for pointer alignment */
if((((uintptr_t) blit->src) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0)
VG_LITE_RETURN_INV("Src buffer ptr (0x%X) not aligned to %d.", (size_t) blit->src, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
/* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */
/* Test for stride alignment */
if((blit->src_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0)
VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.", blit->src_stride,
LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
/* Test for stride alignment */
if((blit->dst_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0)
VG_LITE_RETURN_INV("Dest buffer stride (%d px) not aligned to %d px.", blit->dst_stride,
LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
if((lv_area_get_width(&blit->src_area) != lv_area_get_width(&blit->dst_area)) ||
(lv_area_get_height(&blit->src_area) != lv_area_get_height(&blit->dst_area)))
VG_LITE_RETURN_INV("Src and dest buffer areas are not equal.");
return LV_RES_OK;
}
static void _align_x(lv_area_t * area, lv_color_t ** buf)
{
int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE * 8 / LV_COLOR_DEPTH));
VG_LITE_COND_STOP(alignedAreaStartPx < 0, "Negative X alignment."); VG_LITE_COND_STOP(alignedAreaStartPx < 0, "Negative X alignment.");
area->x1 -= alignedAreaStartPx; area->x1 -= alignedAreaStartPx;
@@ -593,17 +569,17 @@ static void _align_x(lv_area_t * area, lv_color_t ** buf)
*buf += alignedAreaStartPx; *buf += alignedAreaStartPx;
} }
static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride)
{ {
int LineToAlignMem; int LineToAlignMem;
int alignedAreaStartPy; int alignedAreaStartPy;
/* find how many lines of pixels will respect memory alignment requirement */ /* find how many lines of pixels will respect memory alignment requirement */
if(stridePx % (uint32_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE == 0U) { if((stride % (lv_coord_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) == 0x0U) {
alignedAreaStartPy = area->y1; alignedAreaStartPy = area->y1;
} }
else { else {
LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t));
VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX), VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)),
"Complex case: need gcd function."); "Complex case: need gcd function.");
alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem); alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem);
VG_LITE_COND_STOP(alignedAreaStartPy < 0, "Negative Y alignment."); VG_LITE_COND_STOP(alignedAreaStartPy < 0, "Negative Y alignment.");
@@ -611,7 +587,7 @@ static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx)
area->y1 -= alignedAreaStartPy; area->y1 -= alignedAreaStartPy;
area->y2 -= alignedAreaStartPy; area->y2 -= alignedAreaStartPy;
*buf += (uint32_t)alignedAreaStartPy * stridePx; *buf += (uint32_t)(alignedAreaStartPy * stride);
} }
#endif /*VG_LITE_BLIT_SPLIT_ENABLED*/ #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2020-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -41,64 +41,16 @@ extern "C" {
#include "../../../lv_conf_internal.h" #include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "lv_gpu_nxp_vglite.h" #include "lv_vglite_utils.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
#ifndef LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT
/** Minimum area (in pixels) to be filled by VG-Lite with 100% opacity*/
#define LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT
/** Minimum area (in pixels) to be filled by VG-Lite with transparency*/
#define LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT
/** Minimum area (in pixels) for image copy with 100% opacity to be handled by VG-Lite*/
#define LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT
/** Minimum invalidated area (in pixels) to be synchronized by VG-Lite during buffer sync */
#define LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT 5000
#endif
#ifndef LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT
/** Minimum area (in pixels) for image copy with transparency to be handled by VG-Lite*/
#define LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT 5000
#endif
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
/**
* BLock Image Transfer descriptor structure
*/
typedef struct {
const lv_color_t * src; /**< Source buffer pointer (must be aligned on 32 bytes)*/
lv_area_t src_area; /**< Area to be copied from source*/
lv_coord_t src_width; /**< Source buffer width*/
lv_coord_t src_height; /**< Source buffer height*/
int32_t src_stride; /**< Source buffer stride in bytes (must be aligned on 16 px)*/
const lv_color_t * dst; /**< Destination buffer pointer (must be aligned on 32 bytes)*/
lv_area_t dst_area; /**< Target area in destination buffer (must be the same as src_area)*/
lv_coord_t dst_width; /**< Destination buffer width*/
lv_coord_t dst_height; /**< Destination buffer height*/
int32_t dst_stride; /**< Destination buffer stride in bytes (must be aligned on 16 px)*/
lv_opa_t opa; /**< Opacity - alpha mix (0 = source not copied, 255 = 100% opaque)*/
uint32_t angle; /**< Rotation angle (1/10 of degree)*/
uint32_t zoom; /**< 256 = no zoom (1:1 scale ratio)*/
lv_point_t pivot; /**< The coordinates of rotation pivot in source image buffer*/
} lv_gpu_nxp_vglite_blit_info_t;
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
@@ -106,35 +58,52 @@ typedef struct {
/** /**
* Fill area, with optional opacity. * Fill area, with optional opacity.
* *
* @param[in/out] dest_buf Destination buffer pointer (must be aligned on 32 bytes) * @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_width Destination buffer width in pixels (must be aligned on 16 px) * @param[in] color Color
* @param[in] dest_height Destination buffer height in pixels
* @param[in] fill_area Area to be filled
* @param[in] color Fill color
* @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill) * @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill)
*
* @retval LV_RES_OK Fill completed * @retval LV_RES_OK Fill completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa);
const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa);
/** /**
* BLock Image Transfer. * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects.
* By default, image is copied directly, with optional opacity.
*
* @param[in/out] dest_buf Destination buffer
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf Source buffer
* @param[in] src_area Source area with relative coordinates of source buffer
* @param[in] src_stride Stride of source buffer in pixels
* @param[in] opa Opacity
* *
* @param[in] blit Description of the transfer
* @retval LV_RES_OK Transfer complete * @retval LV_RES_OK Transfer complete
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit); lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
lv_opa_t opa);
/** /**
* BLock Image Transfer with transformation. * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation.
* By default, image is copied directly, with optional opacity.
*
* @param[in/out] dest_buf Destination buffer
* @param[in] dest_area Area with relative coordinates of destination buffer
* @param[in] dest_stride Stride of destination buffer in pixels
* @param[in] src_buf Source buffer
* @param[in] src_area Source area with relative coordinates of source buffer
* @param[in] src_stride Stride of source buffer in pixels
* @param[in] dsc Image descriptor
* *
* @param[in] blit Description of the transfer
* @retval LV_RES_OK Transfer complete * @retval LV_RES_OK Transfer complete
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/ */
lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit); lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
const lv_draw_img_dsc_t * dsc);
/********************** /**********************
* MACROS * MACROS

View File

@@ -0,0 +1,138 @@
/**
* @file lv_draw_vglite_line.c
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vglite_line.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "lv_vglite_buf.h"
#include <math.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_res_t lv_gpu_nxp_vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2,
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_path_t path;
vg_lite_color_t vgcol; /* vglite takes ABGR */
vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
vg_lite_cap_style_t cap_style = (dsc->round_start || dsc->round_end) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
vg_lite_join_style_t join_style = (dsc->round_start || dsc->round_end) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER;
bool is_dashed = (dsc->dash_width && dsc->dash_gap);
vg_lite_float_t stroke_dash_pattern[2] = {0, 0};
uint32_t stroke_dash_count = 0;
vg_lite_float_t stroke_dash_phase = 0;
if(is_dashed) {
stroke_dash_pattern[0] = (vg_lite_float_t)dsc->dash_width;
stroke_dash_pattern[1] = (vg_lite_float_t)dsc->dash_gap;
stroke_dash_count = sizeof(stroke_dash_pattern) / sizeof(vg_lite_float_t);
stroke_dash_phase = (vg_lite_float_t)dsc->dash_width / 2;
}
/* Choose vglite blend mode based on given lvgl blend mode */
vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode);
/*** Init path ***/
lv_coord_t width = dsc->width;
int32_t line_path[] = { /*VG line path*/
VLC_OP_MOVE, point1->x, point1->y,
VLC_OP_LINE, point2->x, point2->y,
VLC_OP_END
};
err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(line_path), line_path,
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_color32_t col32 = { .full = lv_color_to32(dsc->color) }; /*Convert color to RGBA8888*/
vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK)
VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
/*** Draw line ***/
err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH);
VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed.");
err = vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count,
stroke_dash_phase, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Set stroke failed.");
err = vg_lite_update_stroke(&path);
VG_LITE_ERR_RETURN_INV(err, "Update stroke failed.");
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Draw line failed.");
if(lv_vglite_run() != LV_RES_OK)
VG_LITE_RETURN_INV("Run failed.");
err = vg_lite_clear_path(&path);
VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
return LV_RES_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -0,0 +1,83 @@
/**
* @file lv_draw_vglite_line.h
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef LV_DRAW_VGLITE_LINE_H
#define LV_DRAW_VGLITE_LINE_H
#ifdef __cplusplus
extern "C"
{
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "lv_vglite_utils.h"
#include "../../lv_draw_line.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Draw line shape with effects
*
* @param[in] point1 Starting point with relative coordinates
* @param[in] point2 Ending point with relative coordinates
* @param[in] clip_area Clipping area with relative coordinates to dest buff
* @param[in] dsc Line description structure (width, rounded ending, opacity, ...)
*
* @retval LV_RES_OK Draw completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/
lv_res_t lv_gpu_nxp_vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2,
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_NXP_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_VGLITE_RECT_H*/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2021, 2022 NXP * Copyright 2021-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -34,10 +34,28 @@
#include "lv_draw_vglite_rect.h" #include "lv_draw_vglite_rect.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "lv_vglite_buf.h"
#include <math.h>
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
/*********************
* DEFINES
*********************/
/* Path data sizes for different elements */
#define CUBIC_PATH_DATA_SIZE 7 /* 1 opcode, 6 arguments */
#define LINE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
#define MOVE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
#define END_PATH_DATA_SIZE 1 /* 1 opcode, 0 arguments */
/* Maximum possible rectangle path size
* is in the rounded rectangle case:
* - 1 move for the path start
* - 4 cubics for the corners
* - 4 lines for the sides
* - 1 end for the path end */
#define RECT_PATH_DATA_MAX_SIZE 1 * MOVE_PATH_DATA_SIZE + 4 * CUBIC_PATH_DATA_SIZE + 4 * LINE_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE
/********************** /**********************
* TYPEDEFS * TYPEDEFS
@@ -47,6 +65,18 @@
* STATIC PROTOTYPES * STATIC PROTOTYPES
**********************/ **********************/
/**
* Generates path data for rectangle drawing.
*
* @param[in/out] path The path data to initialize
* @param[in/out] path_size The resulting size of the created path data
* @param[in] dsc The style descriptor for the rectangle to be drawn
* @param[in] coords The coordinates of the rectangle to be drawn
*/
static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
lv_coord_t radius,
const lv_area_t * coords);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
**********************/ **********************/
@@ -59,94 +89,37 @@
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_rect_dsc_t * dsc)
{ {
vg_lite_buffer_t vgbuf;
vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_error_t err = VG_LITE_SUCCESS;
lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area);
lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area);
vg_lite_path_t path;
vg_lite_color_t vgcol; /* vglite takes ABGR */
vg_lite_matrix_t matrix;
lv_coord_t width = lv_area_get_width(coords); lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords); lv_coord_t height = lv_area_get_height(coords);
vg_lite_linear_gradient_t gradient; vg_lite_color_t vgcol;
vg_lite_matrix_t * grad_matrix; lv_coord_t radius = dsc->radius;
vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
if(dsc->radius < 0) if(dsc->radius < 0)
return LV_RES_INV; return LV_RES_INV;
/* Make areas relative to draw buffer */
lv_area_t rel_coords;
lv_area_copy(&rel_coords, coords);
lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
lv_area_t rel_clip;
lv_area_copy(&rel_clip, draw_ctx->clip_area);
lv_area_move(&rel_clip, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
/*** Init destination buffer ***/
if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t),
(const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK)
VG_LITE_RETURN_INV("Init buffer failed.");
/*** Init path ***/ /*** Init path ***/
int32_t rad = dsc->radius; int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
if(dsc->radius == LV_RADIUS_CIRCLE) { uint32_t path_data_size;
rad = (width > height) ? height / 2 : width / 2; lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
} vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW;
if((dsc->radius == LV_RADIUS_CIRCLE) && (width == height)) {
float tang = ((float)rad * BEZIER_OPTIM_CIRCLE);
int32_t cpoff = (int32_t)tang;
int32_t circle_path[] = { /*VG circle path*/
VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1,
VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */
VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */
VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */
VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */
VLC_OP_END
};
err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(circle_path), circle_path,
(vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1,
((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f);
}
else if(dsc->radius > 0) {
float tang = ((float)rad * BEZIER_OPTIM_CIRCLE);
int32_t cpoff = (int32_t)tang;
int32_t rounded_path[] = { /*VG rounded rectangular path*/
VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1,
VLC_OP_LINE, rel_coords.x2 - rad + 1, rel_coords.y1, /* top */
VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */
VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 - rad + 1, /* right */
VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */
VLC_OP_LINE, rel_coords.x1 + rad, rel_coords.y2 + 1, /* bottom */
VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */
VLC_OP_LINE, rel_coords.x1, rel_coords.y1 + rad, /* left */
VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */
VLC_OP_END
};
err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(rounded_path), rounded_path,
(vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1,
((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f);
}
else {
int32_t rect_path[] = { /*VG rectangular path*/
VLC_OP_MOVE, rel_coords.x1, rel_coords.y1,
VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y1,
VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 + 1,
VLC_OP_LINE, rel_coords.x1, rel_coords.y2 + 1,
VLC_OP_LINE, rel_coords.x1, rel_coords.y1,
VLC_OP_END
};
err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(rect_path), rect_path,
(vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1,
((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f);
}
vg_lite_path_t path;
err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
VG_LITE_ERR_RETURN_INV(err, "Init path failed."); VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix); vg_lite_identity(&matrix);
vg_lite_matrix_t * grad_matrix;
vg_lite_linear_gradient_t gradient;
/*** Init Color/Gradient ***/ /*** Init Color/Gradient ***/
if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) { if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
uint32_t colors[2]; uint32_t colors[2];
@@ -154,18 +127,14 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_
lv_color32_t col32[2]; lv_color32_t col32[2];
/* Gradient setup */ /* Gradient setup */
uint8_t cnt = MAX(dsc->bg_grad.stops_count, 2); uint8_t cnt = LV_MAX(dsc->bg_grad.stops_count, 2);
for(uint8_t i = 0; i < cnt; i++) { for(uint8_t i = 0; i < cnt; i++) {
col32[i].full = lv_color_to32(dsc->bg_grad.stops[i].color); /*Convert color to RGBA8888*/ col32[i].full = lv_color_to32(dsc->bg_grad.stops[i].color); /*Convert color to RGBA8888*/
stops[i] = dsc->bg_grad.stops[i].frac; stops[i] = dsc->bg_grad.stops[i].frac;
#if LV_COLOR_DEPTH==16
colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.blue << 16) | vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_ABGR8888 : VG_LITE_ARGB8888;
((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.red; if(lv_vglite_premult_and_swizzle(&colors[i], col32[i], dsc->bg_opa, color_format) != LV_RES_OK)
#else /*LV_COLOR_DEPTH==32*/ VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
/* watchout: red and blue color components are inverted versus vg_lite_color_t order */
colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.red << 16) |
((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.blue;
#endif
} }
lv_memzero(&gradient, sizeof(vg_lite_linear_gradient_t)); lv_memzero(&gradient, sizeof(vg_lite_linear_gradient_t));
@@ -181,7 +150,7 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_
grad_matrix = vg_lite_get_grad_matrix(&gradient); grad_matrix = vg_lite_get_grad_matrix(&gradient);
vg_lite_identity(grad_matrix); vg_lite_identity(grad_matrix);
vg_lite_translate((float)rel_coords.x1, (float)rel_coords.y1, grad_matrix); vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix);
if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) { if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix); vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix);
@@ -192,39 +161,22 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_
} }
} }
lv_opa_t bg_opa = dsc->bg_opa;
lv_color32_t bg_col32 = {.full = lv_color_to32(dsc->bg_color)}; /*Convert color to RGBA8888*/ lv_color32_t bg_col32 = {.full = lv_color_to32(dsc->bg_color)}; /*Convert color to RGBA8888*/
if(bg_opa <= (lv_opa_t)LV_OPA_MAX) { vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
/* Only pre-multiply color if hardware pre-multiplication is not present */ if(lv_vglite_premult_and_swizzle(&vgcol, bg_col32, dsc->bg_opa, color_format) != LV_RES_OK)
if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
bg_col32.ch.red = (uint8_t)(((uint16_t)bg_col32.ch.red * bg_opa) >> 8);
bg_col32.ch.green = (uint8_t)(((uint16_t)bg_col32.ch.green * bg_opa) >> 8);
bg_col32.ch.blue = (uint8_t)(((uint16_t)bg_col32.ch.blue * bg_opa) >> 8);
}
bg_col32.ch.alpha = bg_opa;
}
#if LV_COLOR_DEPTH==16
vgcol = bg_col32.full;
#else /*LV_COLOR_DEPTH==32*/
vgcol = ((uint32_t)bg_col32.ch.alpha << 24) | ((uint32_t)bg_col32.ch.blue << 16) |
((uint32_t)bg_col32.ch.green << 8) | (uint32_t)bg_col32.ch.red;
#endif
/*Clean & invalidate cache*/
lv_vglite_invalidate_cache();
/*** Draw rectangle ***/ /*** Draw rectangle ***/
if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) { if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
} }
else { else {
err = vg_lite_draw_gradient(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER);
} }
VG_LITE_ERR_RETURN_INV(err, "Draw gradient failed."); VG_LITE_ERR_RETURN_INV(err, "Draw gradient failed.");
err = vg_lite_finish(); if(lv_vglite_run() != LV_RES_OK)
VG_LITE_ERR_RETURN_INV(err, "Finish failed."); VG_LITE_RETURN_INV("Run failed.");
err = vg_lite_clear_path(&path); err = vg_lite_clear_path(&path);
VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
@@ -237,6 +189,261 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_
return LV_RES_OK; return LV_RES_OK;
} }
lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_rect_dsc_t * dsc, bool border)
{
vg_lite_error_t err = VG_LITE_SUCCESS;
vg_lite_color_t vgcol; /* vglite takes ABGR */
lv_coord_t radius = dsc->radius;
vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
if(radius < 0)
return LV_RES_INV;
if(border) {
/* Draw border - only has radius if object has radius*/
lv_coord_t border_half = (lv_coord_t)floor(dsc->border_width / 2.0f);
if(radius > border_half)
radius = radius - border_half;
}
else {
/* Draw outline - always has radius, leave the same radius in the circle case */
lv_coord_t outline_half = (lv_coord_t)ceil(dsc->outline_width / 2.0f);
if(radius < (lv_coord_t)LV_RADIUS_CIRCLE - outline_half)
radius = radius + outline_half;
}
vg_lite_cap_style_t cap_style = (radius) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
vg_lite_join_style_t join_style = (radius) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER;
/* Choose vglite blend mode based on given lvgl blend mode */
vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode);
/*** Init path ***/
int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
uint32_t path_data_size;
lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW;
vg_lite_path_t path;
err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_opa_t opa;
lv_color32_t col32;
lv_coord_t line_width;
if(border) {
opa = dsc->border_opa;
col32.full = lv_color_to32(dsc->border_color); /*Convert color to RGBA8888*/
line_width = dsc->border_width;
}
else {
opa = dsc->outline_opa;
col32.full = lv_color_to32(dsc->outline_color); /*Convert color to RGBA8888*/
line_width = dsc->outline_width;
}
vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK)
VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
/*** Draw border ***/
err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH);
VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed.");
err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Set stroke failed.");
err = vg_lite_update_stroke(&path);
VG_LITE_ERR_RETURN_INV(err, "Update stroke failed.");
err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol);
VG_LITE_ERR_RETURN_INV(err, "Draw border failed.");
if(lv_vglite_run() != LV_RES_OK)
VG_LITE_RETURN_INV("Run failed.");
err = vg_lite_clear_path(&path);
VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
return LV_RES_OK;
}
static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
lv_coord_t radius,
const lv_area_t * coords)
{
lv_coord_t rect_width = lv_area_get_width(coords);
lv_coord_t rect_height = lv_area_get_height(coords);
/* Get the final radius. Can't be larger than the half of the shortest side */
int32_t shortest_side = LV_MIN(rect_width, rect_height);
int32_t final_radius = LV_MIN(radius, shortest_side / 2);
/* Path data element index */
uint8_t pidx = 0;
if((radius == (lv_coord_t)LV_RADIUS_CIRCLE) && (rect_width == rect_height)) {
/* Get the control point offset for rounded cases */
int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
/* Circle case */
/* Starting point */
path_data[pidx++] = VLC_OP_MOVE;
path_data[pidx++] = coords->x1 + final_radius;
path_data[pidx++] = coords->y1;
/* Top-right arc */
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = cpoff;
path_data[pidx++] = 0;
path_data[pidx++] = final_radius;
path_data[pidx++] = final_radius - cpoff;
path_data[pidx++] = final_radius;
path_data[pidx++] = final_radius;
/* Bottom-right arc*/
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0;
path_data[pidx++] = cpoff;
path_data[pidx++] = cpoff - final_radius;
path_data[pidx++] = final_radius;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = final_radius;
/* Bottom-left arc */
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0 - cpoff;
path_data[pidx++] = 0;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = cpoff - final_radius;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = 0 - final_radius;
/* Top-left arc*/
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0;
path_data[pidx++] = 0 - cpoff;
path_data[pidx++] = final_radius - cpoff;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = final_radius;
path_data[pidx++] = 0 - final_radius;
/* Ending point */
path_data[pidx++] = VLC_OP_END;
}
else if(radius > 0) {
/* Get the control point offset for rounded cases */
int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
/* Rounded rectangle case */
/* Starting point */
path_data[pidx++] = VLC_OP_MOVE;
path_data[pidx++] = coords->x1 + final_radius;
path_data[pidx++] = coords->y1;
/* Top side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x2 - final_radius + 1; // Extended for VGLite
path_data[pidx++] = coords->y1;
/* Top-right corner */
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = cpoff;
path_data[pidx++] = 0;
path_data[pidx++] = final_radius;
path_data[pidx++] = final_radius - cpoff;
path_data[pidx++] = final_radius;
path_data[pidx++] = final_radius;
/* Right side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
path_data[pidx++] = coords->y2 - final_radius + 1; // Extended for VGLite
/* Bottom-right corner*/
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0;
path_data[pidx++] = cpoff;
path_data[pidx++] = cpoff - final_radius;
path_data[pidx++] = final_radius;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = final_radius;
/* Bottom side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x1 + final_radius;
path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
/* Bottom-left corner */
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0 - cpoff;
path_data[pidx++] = 0;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = cpoff - final_radius;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = 0 - final_radius;
/* Left side*/
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x1;
path_data[pidx++] = coords->y1 + final_radius;
/* Top-left corner */
path_data[pidx++] = VLC_OP_CUBIC_REL;
path_data[pidx++] = 0;
path_data[pidx++] = 0 - cpoff;
path_data[pidx++] = final_radius - cpoff;
path_data[pidx++] = 0 - final_radius;
path_data[pidx++] = final_radius;
path_data[pidx++] = 0 - final_radius;
/* Ending point */
path_data[pidx++] = VLC_OP_END;
}
else {
/* Non-rounded rectangle case */
/* Starting point */
path_data[pidx++] = VLC_OP_MOVE;
path_data[pidx++] = coords->x1;
path_data[pidx++] = coords->y1;
/* Top side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
path_data[pidx++] = coords->y1;
/* Right side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
/* Bottom side */
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x1;
path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
/* Left side*/
path_data[pidx++] = VLC_OP_LINE;
path_data[pidx++] = coords->x1;
path_data[pidx++] = coords->y1;
/* Ending point */
path_data[pidx++] = VLC_OP_END;
}
/* Resulting path size */
*path_data_size = pidx * sizeof(int32_t);
}
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/

View File

@@ -6,7 +6,7 @@
/** /**
* MIT License * MIT License
* *
* Copyright 2021, 2022 NXP * Copyright 2021-2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -40,7 +40,7 @@ extern "C" {
#include "../../../lv_conf_internal.h" #include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "lv_gpu_nxp_vglite.h" #include "lv_vglite_utils.h"
#include "../../lv_draw_rect.h" #include "../../lv_draw_rect.h"
/********************* /*********************
@@ -56,13 +56,33 @@ extern "C" {
**********************/ **********************/
/** /**
* Draw rectangle shape with effects (rounded corners, gradient) * Draw rectangle background with effects (rounded corners, gradient)
*
* @param[in] coords Coordinates of the rectangle background (relative to dest buff)
* @param[in] clip_area Clipping area with relative coordinates to dest buff
* @param[in] dsc Description of the rectangle background
*
* @retval LV_RES_OK Draw completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
* *
* @param draw_ctx drawing context
* @param dsc description of the rectangle
* @param coords the area where rectangle is clipped
*/ */
lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_rect_dsc_t * dsc);
/**
* Draw rectangle border/outline shape with effects (rounded corners, opacity)
*
* @param[in] coords Coordinates of the rectangle border/outline (relative to dest buff)
* @param[in] clip_area Clipping area with relative coordinates to dest buff
* @param[in] dsc Description of the rectangle border/outline
* @param[in] border True for border, False for outline
*
* @retval LV_RES_OK Draw completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*
*/
lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area,
const lv_draw_rect_dsc_t * dsc, bool border);
/********************** /**********************
* MACROS * MACROS

View File

@@ -1,153 +0,0 @@
/**
* @file lv_gpu_nxp_vglite.c
*
*/
/**
* MIT License
*
* Copyright 2020-2022 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_gpu_nxp_vglite.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "../../../core/lv_refr.h"
#if BLIT_DBG_AREAS
#include "lv_draw_vglite_blend.h"
#endif
/*********************
* DEFINES
*********************/
#if LV_COLOR_DEPTH==16
#define VG_LITE_PX_FMT VG_LITE_RGB565
#elif LV_COLOR_DEPTH==32
#define VG_LITE_PX_FMT VG_LITE_BGRA8888
#else
#error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32.
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride,
const lv_color_t * ptr, bool source)
{
/*Test for memory alignment*/
if((((uintptr_t)ptr) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U)
VG_LITE_RETURN_INV("%s buffer (0x%x) not aligned to %d.", source ? "Src" : "Dest",
(size_t) ptr, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
/*Test for stride alignment*/
if(source && (stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t))) != 0x0U)
VG_LITE_RETURN_INV("Src buffer stride (%d bytes) not aligned to %d bytes.", stride,
LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t));
vgbuf->format = VG_LITE_PX_FMT;
vgbuf->tiled = VG_LITE_LINEAR;
vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE;
vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE;
vgbuf->width = (int32_t)width;
vgbuf->height = (int32_t)height;
vgbuf->stride = (int32_t)stride;
lv_memzero(&vgbuf->yuv, sizeof(vgbuf->yuv));
vgbuf->memory = (void *)ptr;
vgbuf->address = (uint32_t)vgbuf->memory;
vgbuf->handle = NULL;
return LV_RES_OK;
}
#if BLIT_DBG_AREAS
void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height,
lv_area_t * fill_area, lv_color_t color)
{
lv_area_t a;
/* top line */
a.x1 = fill_area->x1;
a.x2 = fill_area->x2;
a.y1 = fill_area->y1;
a.y2 = fill_area->y1;
lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
/* bottom line */
a.x1 = fill_area->x1;
a.x2 = fill_area->x2;
a.y1 = fill_area->y2;
a.y2 = fill_area->y2;
lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
/* left line */
a.x1 = fill_area->x1;
a.x2 = fill_area->x1;
a.y1 = fill_area->y1;
a.y2 = fill_area->y2;
lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
/* right line */
a.x1 = fill_area->x2;
a.x2 = fill_area->x2;
a.y1 = fill_area->y1;
a.y2 = fill_area->y2;
lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
}
#endif /* BLIT_DBG_AREAS */
void lv_vglite_invalidate_cache(void)
{
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
if(disp->driver->clean_dcache_cb)
disp->driver->clean_dcache_cb(disp->driver);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -0,0 +1,143 @@
/**
* @file lv_vglite_buf.c
*
*/
/**
* MIT License
*
* Copyright 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_buf.h"
#if LV_USE_GPU_NXP_VG_LITE
/*********************
* DEFINES
*********************/
#if LV_COLOR_DEPTH == 16
#define VG_LITE_PX_FMT VG_LITE_RGB565
#elif LV_COLOR_DEPTH == 32
#define VG_LITE_PX_FMT VG_LITE_BGRA8888
#else
#error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32.
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride);
static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf);
static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf,
const lv_area_t * area, lv_coord_t stride);
/**********************
* STATIC VARIABLES
**********************/
static vg_lite_buffer_t dest_vgbuf;
static vg_lite_buffer_t src_vgbuf;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride)
{
lv_vglite_set_dest_buf(buf, area, stride);
}
vg_lite_buffer_t * lv_vglite_get_dest_buf(void)
{
return &dest_vgbuf;
}
vg_lite_buffer_t * lv_vglite_get_src_buf(void)
{
return &src_vgbuf;
}
void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf)
{
lv_vglite_set_buf_ptr(&dest_vgbuf, buf);
}
void lv_vglite_set_src_buf_ptr(const lv_color_t * buf)
{
lv_vglite_set_buf_ptr(&src_vgbuf, buf);
}
void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride)
{
if(src_vgbuf.memory != (void *)buf)
lv_vglite_set_buf(&src_vgbuf, buf, area, stride);
}
/**********************
* STATIC FUNCTIONS
**********************/
static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride)
{
lv_vglite_set_buf(&dest_vgbuf, buf, area, stride);
}
static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf)
{
vgbuf->memory = (void *)buf;
vgbuf->address = (uint32_t)vgbuf->memory;
}
static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf,
const lv_area_t * area, lv_coord_t stride)
{
vgbuf->format = VG_LITE_PX_FMT;
vgbuf->tiled = VG_LITE_LINEAR;
vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE;
vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE;
vgbuf->width = (int32_t)lv_area_get_width(area);
vgbuf->height = (int32_t)lv_area_get_height(area);
vgbuf->stride = (int32_t)(stride) * sizeof(lv_color_t);
lv_memset(&vgbuf->yuv, 0, sizeof(vgbuf->yuv));
vgbuf->memory = (void *)buf;
vgbuf->address = (uint32_t)vgbuf->memory;
vgbuf->handle = NULL;
}
#endif /*LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -0,0 +1,113 @@
/**
* @file lv_vglite_buf.h
*
*/
/**
* MIT License
*
* Copyright 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef LV_VGLITE_BUF_H
#define LV_VGLITE_BUF_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "vg_lite.h"
#include "../../sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init vglite destination buffer. It will be done once per frame.
*
* @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode)
* @param[in] area Destination buffer area (for width and height)
* @param[in] stride Stride of destination buffer
*/
void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride);
/**
* Get vglite destination buffer pointer.
*
* @retval The vglite destination buffer
*/
vg_lite_buffer_t * lv_vglite_get_dest_buf(void);
/**
* Get vglite source buffer pointer.
*
* @retval The vglite source buffer
*/
vg_lite_buffer_t * lv_vglite_get_src_buf(void);
/**
* Set vglite destination buffer address only.
*
* @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode)
*/
void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf);
/**
* Set vglite source buffer address only.
*
* @param[in] buf Source buffer address
*/
void lv_vglite_set_src_buf_ptr(const lv_color_t * buf);
/**
* Set vglite source buffer. It will be done only if buffer addreess is different.
*
* @param[in] buf Source buffer address
* @param[in] area Source buffer area (for width and height)
* @param[in] stride Stride of source buffer
*/
void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GPU_NXP_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VGLITE_BUF_H*/

View File

@@ -0,0 +1,149 @@
/**
* @file lv_vglite_utils.c
*
*/
/**
* MIT License
*
* Copyright 2022, 2023 NXP
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph)
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vglite_utils.h"
#if LV_USE_GPU_NXP_VG_LITE
#include "../../../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**
* Clean and invalidate cache.
*/
static inline void invalidate_cache(void);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_res_t lv_vglite_run(void)
{
invalidate_cache();
VG_LITE_ERR_RETURN_INV(vg_lite_flush(), "Flush failed.");
return LV_RES_OK;
}
lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa,
vg_lite_buffer_format_t vg_col_format)
{
lv_color32_t lv_col32_premul = lv_col32;
if(opa <= (lv_opa_t)LV_OPA_MAX) {
/* Only pre-multiply color if hardware pre-multiplication is not present */
if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
lv_col32_premul.ch.red = (uint8_t)(((uint16_t)lv_col32.ch.red * opa) >> 8);
lv_col32_premul.ch.green = (uint8_t)(((uint16_t)lv_col32.ch.green * opa) >> 8);
lv_col32_premul.ch.blue = (uint8_t)(((uint16_t)lv_col32.ch.blue * opa) >> 8);
}
lv_col32_premul.ch.alpha = opa;
}
switch(vg_col_format) {
case VG_LITE_BGRA8888:
*vg_col32 = lv_col32_premul.full;
break;
case VG_LITE_RGBA8888:
*vg_col32 = ((uint32_t)lv_col32_premul.ch.red << 24) | ((uint32_t)lv_col32_premul.ch.green << 16) |
((uint32_t)lv_col32_premul.ch.blue << 8) | (uint32_t)lv_col32_premul.ch.alpha;
break;
case VG_LITE_ABGR8888:
*vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.blue << 16) |
((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.red;
break;
case VG_LITE_ARGB8888:
*vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.red << 16) |
((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.blue;
break;
default:
return LV_RES_INV;
}
return LV_RES_OK;
}
vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode)
{
vg_lite_blend_t vg_blend_mode;
switch(lv_blend_mode) {
case LV_BLEND_MODE_ADDITIVE:
vg_blend_mode = VG_LITE_BLEND_ADDITIVE;
break;
case LV_BLEND_MODE_SUBTRACTIVE:
vg_blend_mode = VG_LITE_BLEND_SUBTRACT;
break;
case LV_BLEND_MODE_MULTIPLY:
vg_blend_mode = VG_LITE_BLEND_MULTIPLY;
break;
case LV_BLEND_MODE_REPLACE:
vg_blend_mode = VG_LITE_BLEND_NONE;
break;
default:
vg_blend_mode = VG_LITE_BLEND_SRC_OVER;
break;
}
return vg_blend_mode;
}
/**********************
* STATIC FUNCTIONS
**********************/
static inline void invalidate_cache(void)
{
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
if(disp->driver->clean_dcache_cb)
disp->driver->clean_dcache_cb(disp->driver);
}
#endif /*LV_USE_GPU_NXP_VG_LITE*/

View File

@@ -1,12 +1,12 @@
/** /**
* @file lv_gpu_nxp_vglite.h * @file lv_vglite_utils.h
* *
*/ */
/** /**
* MIT License * MIT License
* *
* Copyright 2020-2022 NXP * Copyright 2022, 2023 NXP
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,8 +27,8 @@
* *
*/ */
#ifndef LV_GPU_NXP_VGLITE_H #ifndef LV_VGLITE_UTILS_H
#define LV_GPU_NXP_VGLITE_H #define LV_VGLITE_UTILS_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -43,40 +43,21 @@ extern "C" {
#include "vg_lite.h" #include "vg_lite.h"
#include "../../sw/lv_draw_sw.h" #include "../../sw/lv_draw_sw.h"
#include "../../../misc/lv_log.h" #include "../../../misc/lv_log.h"
#include "fsl_debug_console.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
/** Use this symbol as limit to disable feature (value has to be larger than supported resolution) */
#define LV_GPU_NXP_VG_LITE_FEATURE_DISABLED (1920*1080+1)
/** Stride in px required by VG-Lite HW. Don't change this. */
#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U
#ifndef LV_GPU_NXP_VG_LITE_LOG_ERRORS #ifndef LV_GPU_NXP_VG_LITE_LOG_ERRORS
/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ /** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/
#define LV_GPU_NXP_VG_LITE_LOG_ERRORS 1 #define LV_GPU_NXP_VG_LITE_LOG_ERRORS 1
#endif #endif
#ifndef LV_GPU_NXP_VG_LITE_LOG_TRACES #ifndef LV_GPU_NXP_VG_LITE_LOG_TRACES
/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ /** Enable logging of VG-Lite traces (\see LV_LOG_ERROR)*/
#define LV_GPU_NXP_VG_LITE_LOG_TRACES 0 #define LV_GPU_NXP_VG_LITE_LOG_TRACES 0
#endif #endif
/* Draw rectangles around BLIT tiles */
#define BLIT_DBG_AREAS 0
/* Print detailed info to SDK console (NOT to LVGL log system) */
#define BLIT_DBG_VERBOSE 0
/* Verbose debug print */
#if BLIT_DBG_VERBOSE
#define PRINT_BLT PRINTF
#else
#define PRINT_BLT(...)
#endif
/* The optimal Bezier control point offset for radial unit /* The optimal Bezier control point offset for radial unit
* see: https://spencermortensen.com/articles/bezier-circle/ * see: https://spencermortensen.com/articles/bezier-circle/
@@ -95,36 +76,35 @@ extern "C" {
**********************/ **********************/
/** /**
* Fills vg_lite_buffer_t structure according given parameters. * Premultiplies and swizzles given LVGL 32bit color to obtain vglite color.
* *
* @param[in/out] vgbuf Buffer structure to be filled * @param[in/out] vg_col32 The obtained vglite color
* @param[in] width Width of buffer in pixels * @param[in] lv_col32 The initial LVGL 32bit color
* @param[in] height Height of buffer in pixels * @param[in] opa The opacity to premultiply with
* @param[in] stride Stride of the buffer in bytes * @param[in] vg_col_format The format of the resulting vglite color
* @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements)
* @param[in] source Boolean to check if this is a source buffer
*/
lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride,
const lv_color_t * ptr, bool source);
#if BLIT_DBG_AREAS
/**
* Draw a simple rectangle, 1 px line width.
* *
* @param dest_buf Destination buffer * @retval LV_RES_OK Operation completed
* @param dest_width Destination buffer width (must be aligned on 16px) * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
* @param dest_height Destination buffer height
* @param fill_area Rectangle coordinates
* @param color Rectangle color
*/ */
void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa,
lv_area_t * fill_area, lv_color_t color); vg_lite_buffer_format_t vg_col_format);
#endif
/** /**
* Clean & invalidate cache. * Get vglite blend mode.
*
* @param[in] lv_blend_mode The LVGL blend mode
*
* @retval The vglite blend mode
*/ */
void lv_vglite_invalidate_cache(void); vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode);
/**
* Clear cache and flush command to VG-Lite.
*
* @retval LV_RES_OK Run completed
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
*/
lv_res_t lv_vglite_run(void);
/********************** /**********************
* MACROS * MACROS
@@ -142,7 +122,8 @@ void lv_vglite_invalidate_cache(void);
#define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \ #define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \
do { \ do { \
if(err != VG_LITE_SUCCESS) { \ if(err != VG_LITE_SUCCESS) { \
LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ LV_LOG_ERROR(fmt" (err = %d)", \
err, ##__VA_ARGS__); \
return LV_RES_INV; \ return LV_RES_INV; \
} \ } \
} while (0) } while (0)
@@ -158,7 +139,7 @@ void lv_vglite_invalidate_cache(void);
#if LV_GPU_NXP_VG_LITE_LOG_TRACES #if LV_GPU_NXP_VG_LITE_LOG_TRACES
#define VG_LITE_LOG_TRACE(fmt, ...) \ #define VG_LITE_LOG_TRACE(fmt, ...) \
do { \ do { \
LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ LV_LOG(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define VG_LITE_RETURN_INV(fmt, ...) \ #define VG_LITE_RETURN_INV(fmt, ...) \
@@ -182,4 +163,4 @@ void lv_vglite_invalidate_cache(void);
} /*extern "C"*/ } /*extern "C"*/
#endif #endif
#endif /*LV_GPU_NXP_VGLITE_H*/ #endif /*LV_VGLITE_UTILS_H*/

View File

@@ -35,8 +35,12 @@
#include "../draw/arm2d/lv_gpu_arm2d.h" #include "../draw/arm2d/lv_gpu_arm2d.h"
#endif #endif
#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "../draw/nxp/lv_gpu_nxp.h" #include "../draw/nxp/vglite/lv_draw_vglite.h"
#endif
#if LV_USE_GPU_NXP_PXP
#include "../draw/nxp/pxp/lv_draw_pxp.h"
#endif #endif
#if LV_USE_THEME_DEFAULT #if LV_USE_THEME_DEFAULT
@@ -110,10 +114,14 @@ void lv_disp_drv_init(lv_disp_drv_t * driver)
driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init; driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init;
driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_deinit; driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_deinit;
driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t); driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t);
#elif LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE #elif LV_USE_GPU_NXP_VG_LITE
driver->draw_ctx_init = lv_draw_nxp_ctx_init; driver->draw_ctx_init = lv_draw_vglite_ctx_init;
driver->draw_ctx_deinit = lv_draw_nxp_ctx_deinit; driver->draw_ctx_deinit = lv_draw_vglite_ctx_deinit;
driver->draw_ctx_size = sizeof(lv_draw_nxp_ctx_t); driver->draw_ctx_size = sizeof(lv_draw_vglite_ctx_t);
#elif LV_USE_GPU_NXP_PXP
driver->draw_ctx_init = lv_draw_pxp_ctx_init;
driver->draw_ctx_deinit = lv_draw_pxp_ctx_deinit;
driver->draw_ctx_size = sizeof(lv_draw_pxp_ctx_t);
#elif LV_USE_DRAW_SDL #elif LV_USE_DRAW_SDL
driver->draw_ctx_init = lv_draw_sdl_init_ctx; driver->draw_ctx_init = lv_draw_sdl_init_ctx;
driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx; driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx;

View File

@@ -64,7 +64,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent)
return obj; return obj;
} }
void lv_animimg_set_src(lv_obj_t * obj, lv_img_dsc_t * dsc[], uint8_t num) void lv_animimg_set_src(lv_obj_t * obj, const void * dsc[], uint8_t num)
{ {
LV_ASSERT_OBJ(obj, MY_CLASS); LV_ASSERT_OBJ(obj, MY_CLASS);
lv_animimg_t * animimg = (lv_animimg_t *)obj; lv_animimg_t * animimg = (lv_animimg_t *)obj;
@@ -103,7 +103,7 @@ void lv_animimg_set_repeat_count(lv_obj_t * obj, uint16_t count)
* Getter functions * Getter functions
*====================*/ *====================*/
lv_img_dsc_t ** lv_animimg_get_src(lv_obj_t * obj) const void ** lv_animimg_get_src(lv_obj_t * obj)
{ {
LV_ASSERT_OBJ(obj, MY_CLASS); LV_ASSERT_OBJ(obj, MY_CLASS);
lv_animimg_t * animimg = (lv_animimg_t *)obj; lv_animimg_t * animimg = (lv_animimg_t *)obj;

View File

@@ -37,7 +37,7 @@ typedef struct {
lv_img_t img; lv_img_t img;
lv_anim_t anim; lv_anim_t anim;
/*picture sequence */ /*picture sequence */
lv_img_dsc_t ** dsc; const void ** dsc;
int8_t pic_count; int8_t pic_count;
} lv_animimg_t; } lv_animimg_t;
@@ -69,7 +69,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent);
* @param dsc pointer to a series images * @param dsc pointer to a series images
* @param num images' number * @param num images' number
*/ */
void lv_animimg_set_src(lv_obj_t * img, lv_img_dsc_t * dsc[], uint8_t num); void lv_animimg_set_src(lv_obj_t * img, const void * dsc[], uint8_t num);
/** /**
* Startup the image animation. * Startup the image animation.
@@ -99,7 +99,7 @@ void lv_animimg_set_repeat_count(lv_obj_t * img, uint16_t count);
* @param img pointer to an animation image object * @param img pointer to an animation image object
* @return a pointer that will point to a series images * @return a pointer that will point to a series images
*/ */
lv_img_dsc_t ** lv_animimg_get_src(lv_obj_t * img); const void ** lv_animimg_get_src(lv_obj_t * img);
/** /**
* Get the image animation images source. * Get the image animation images source.

View File

@@ -44,16 +44,16 @@ void test_animimg_successful_create(void)
void test_animimg_set_src(void) void test_animimg_set_src(void)
{ {
lv_animimg_set_src(animimg, (lv_img_dsc_t **) anim_imgs, 3); lv_animimg_set_src(animimg, (const void **) anim_imgs, 3);
TEST_ASSERT_NOT_NULL(animimg); TEST_ASSERT_NOT_NULL(animimg);
} }
void test_animimg_get_src(void) void test_animimg_get_src(void)
{ {
lv_animimg_set_src(animimg, (lv_img_dsc_t **) anim_imgs, 3); lv_animimg_set_src(animimg, (const void **) anim_imgs, 3);
lv_img_dsc_t ** actual_dsc = lv_animimg_get_src(animimg); const void ** actual_dsc = lv_animimg_get_src(animimg);
TEST_ASSERT_NOT_NULL(actual_dsc); TEST_ASSERT_NOT_NULL(actual_dsc);
TEST_ASSERT_EQUAL_PTR(actual_dsc, anim_imgs); TEST_ASSERT_EQUAL_PTR(actual_dsc, anim_imgs);
@@ -64,7 +64,7 @@ void test_animimg_get_src_count(void)
{ {
uint8_t expected_count = 3; uint8_t expected_count = 3;
lv_animimg_set_src(animimg, (lv_img_dsc_t **) anim_imgs, expected_count); lv_animimg_set_src(animimg, (const void **) anim_imgs, expected_count);
uint8_t actual_count = lv_animimg_get_src_count(animimg); uint8_t actual_count = lv_animimg_get_src_count(animimg);
@@ -95,7 +95,7 @@ void test_animimg_start(void)
{ {
// for lv_animimg_start() to actually work, // for lv_animimg_start() to actually work,
// we need to properly setup the widget beforehand // we need to properly setup the widget beforehand
lv_animimg_set_src(animimg, (lv_img_dsc_t **) anim_imgs, 3); lv_animimg_set_src(animimg, (const void **) anim_imgs, 3);
lv_animimg_set_duration(animimg, 1000); lv_animimg_set_duration(animimg, 1000);
lv_animimg_set_repeat_count(animimg, LV_ANIM_REPEAT_INFINITE); lv_animimg_set_repeat_count(animimg, LV_ANIM_REPEAT_INFINITE);