feat(gpu): reattach nxp pxp vglite accelerators(#3322)
* feat(pxp/vglite) Attach NXP GPUs to the new draw context. Create a single NXP draw layer on top of PXP and VGLITE. Extra changes: 1. Add VGLITE image blits acceleration. 2. Reenable blit split workaround for quality issue in RT500. 3. Increase threshold from 32 to 5000 px to fill/blit with both PXP and VGLITE. 4. Allow to enable both PXP and VGLITE. Add a fallback mechanism: - by default the PXP will try to accelerate. if that is not supported (or fails due to threshold limit condition from 3.) then it will fallback to VGLITE. - if VGLITE does not support that feature (or fails due to threshold limit condition from 3.) the it will fallback to CPU. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(vglite) Add VGLITE support to draw the backgroud of rectangles. optim: draw only a circle when radius has value LV_RADIUS_CIRCLE. optim: to draw rounded corners, use cubic bezier curves Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(vglite) Add VGLITE support to draw arcs. Use up to 4 bezier curves to optimize the drawing of an arc. The arc curve has to be constant when growing the angle: for this we compute sub-arc based on a best approximation of quarter-arc. use dichotomy to find the sub-arc 't' param, instead of tangent approximation. Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(pxp) Add ARGB88888 format support for PXP backend. Supports per pixel and global alpha blending, and combination of alpha blending with recolor feature. Signed-off-by: Jerome Evillard <jerome.evillard@nxp.com> Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(vglite) Add the support of ARGB 32bits color format. Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(vglite) Add VGLITE acceleration support for rotation and zoom. Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(pxp) Add PXP acceleratin to rotate in blit. Applies the rotation on the pxp output. Signed-off-by: Seb Fagard <sebastien.fagard@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp/vglite) Avoid calling the blend callback from image decoded callback. Add lv_gpu_nxp_pxp_blit_transform() and lv_gpu_nxp_vglite_blit_transform(). This will simplify a lot the fallback mechanism and the way of adding new image decoded features. (MGG-884) Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(pxp) Add image rotate 90x. Simplify the two steps process by adding the blit_cover and blit_opa functions. In order to rotate or recolor with opacity, two steps must be fallowed: 1. Run the operation without opa. 2. Blend the result by applying the opa. (MGG-469) Obs: Recolor and rotate is currently not supported with opa or alpha channel.(MGG-883) Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(vglite) Fix incorrect slider widget indicator when vglite acceleration is enabled (MGG-863) Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com> Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp) Fix pxp fill (simple rect draw) on 32 bit color depth. (MGG-890) Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com> * fix(pxp) Separate blit simple by the blit with transformation. While we run into blit with transformation we have to decide if the operation needs to be done in one or two steps. Blit with color format (opa or alpha or chroma key) - require one step: blit_cf(). Blit with rotate or recolor but no color format - require one step: blit_cover(). Blit with rotate or recolor + opa or alpha - require two steps: blit_opa() = blit_cover() + blit_cf(). Blit with rotate or recolor + chroma key - not supported yet. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(pxp) Add support for recolor with chroma-keying. (MGG-434) Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com> * fix(pxp) Fix temporary buffer allocation limit. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp) Add PXP limitation while rotating images not aligned to 16x16 blocks. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(nxp) Add makefiles. Tested with: working-directory: tests/makefile run: make test_file Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * feat(nxp) Update NXP github documentation. (MGG-864) Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(nxp) Move the API comments of global functions only in the H files to make maintenance simpler. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(nxp/vglite) Fixed some warnings. Remove unused variables. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(nxp) lv_draw_nxp_ctx_deinit() shall simply fallback to sofware call. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(nxp) Fallback to software callbacks if need for argb8565 support. 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. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp) Fix wrong demo widget transparency. 1. Fix alpha inverted calculation for fill with opacity. 2. Fix also the ratio of recoloring for chroma key. Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com> * fix(vglite) Remove software pre-multiplication when hardware pre-multiplication is available. (MGG-886) Signed-off-by: Stefan Babatie <stefan.babatie@nxp.com> * doc(vglite) Add vglite initialization info. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp/vglite) Fix unused variable warnings when PXP/VGLite are not enabled simultaneously. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> * fix(pxp) Fixed the color key recoloring on 16 bits color depth. 1. Fixed the arguments of lv_color_mix(), previously was using an inversed logic. But it works anyway. 2. Use LV_COLOR_SET_X for adjusting the channels on both 16 and 32 bits. Fixed the max values. Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com> Co-authored-by: Stefan Babatie <stefan.babatie@nxp.com>
This commit is contained in:
632
src/draw/nxp/pxp/lv_draw_pxp_blend.c
Normal file
632
src/draw/nxp/pxp/lv_draw_pxp_blend.c
Normal file
@@ -0,0 +1,632 @@
|
||||
/**
|
||||
* @file lv_draw_pxp_blend.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_draw_pxp_blend.h"
|
||||
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_COLOR_16_SWAP
|
||||
#error Color swap not implemented. Disable LV_COLOR_16_SWAP feature.
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH==16
|
||||
#define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565
|
||||
#define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565
|
||||
#define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565
|
||||
#elif LV_COLOR_DEPTH==32
|
||||
#define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888
|
||||
#define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888
|
||||
#define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888
|
||||
#elif
|
||||
#error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32.
|
||||
#endif
|
||||
|
||||
#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \
|
||||
|| defined (_WIN64) || defined (__LP64__) || defined (__LLP64__)
|
||||
#define ALIGN_SIZE 8
|
||||
#else
|
||||
#define ALIGN_SIZE 4
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer
|
||||
* with combination of transformation (rotation, scale, recolor) and opacity, alpha channel
|
||||
* or color keying. This requires two steps. First step is used for transformation into
|
||||
* a temporary buffer and the second one will handle the color format or opacity.
|
||||
*
|
||||
* @param[in/out] dest_buf destination buffer
|
||||
* @param[in] dest_area area to be copied from src_buf to dst_buf
|
||||
* @param[in] dest_stride width (stride) of destination buffer in pixels
|
||||
* @param[in] src_buf source buffer
|
||||
* @param[in] src_area source area with absolute coordinates to draw on destination buffer
|
||||
* @param[in] dsc image descriptor
|
||||
* @param[in] cf color format
|
||||
* @retval LV_RES_OK Fill completed
|
||||
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
|
||||
*/
|
||||
static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer
|
||||
* with transformation and full opacity.
|
||||
*
|
||||
* @param[in/out] dest_buf destination buffer
|
||||
* @param[in] dest_area area to be copied from src_buf to dst_buf
|
||||
* @param[in] dest_stride width (stride) of destination buffer in pixels
|
||||
* @param[in] src_buf source buffer
|
||||
* @param[in] src_area source area with absolute coordinates to draw on destination buffer
|
||||
* @param[in] dsc image descriptor
|
||||
* @param[in] cf color format
|
||||
* @retval LV_RES_OK Fill completed
|
||||
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
|
||||
*/
|
||||
static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
|
||||
|
||||
/**
|
||||
* BLock Image Transfer - copy rectangular image from src buffer to dst buffer
|
||||
* without transformation but handling color format or opacity.
|
||||
*
|
||||
* @param[in/out] dest_buf destination buffer
|
||||
* @param[in] dest_area area to be copied from src_buf to dst_buf
|
||||
* @param[in] dest_stride width (stride) of destination buffer in pixels
|
||||
* @param[in] src_buf source buffer
|
||||
* @param[in] src_area source area with absolute coordinates to draw on destination buffer
|
||||
* @param[in] dsc image descriptor
|
||||
* @param[in] cf color format
|
||||
* @retval LV_RES_OK Fill completed
|
||||
* @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS)
|
||||
*/
|
||||
static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#define ROUND_UP(x, align) ((x + (align - 1)) & ~(align - 1))
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
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_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*/
|
||||
pxp_output_buffer_config_t outputConfig = {
|
||||
.pixelFormat = PXP_OUT_PIXEL_FORMAT,
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * fill_area->y1 + fill_area->x1),
|
||||
.buffer1Addr = (uint32_t)NULL,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t),
|
||||
.width = area_w,
|
||||
.height = area_h
|
||||
};
|
||||
|
||||
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig);
|
||||
|
||||
if(opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
/*Simple color fill without opacity - AS disabled*/
|
||||
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
|
||||
}
|
||||
else {
|
||||
/*Fill with opacity - AS used as source (same as OUT)*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = PXP_AS_PIXEL_FORMAT,
|
||||
.bufferAddr = (uint32_t)outputConfig.buffer0Addr,
|
||||
.pitchBytes = outputConfig.pitchBytes
|
||||
};
|
||||
|
||||
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, area_w, area_h);
|
||||
}
|
||||
|
||||
/*Disable PS, use as color generator*/
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(color));
|
||||
|
||||
/**
|
||||
* Configure Porter-Duff blending - src settings are unused for fill without opacity (opa = 0xff).
|
||||
*
|
||||
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
|
||||
* srcFactorMode is actually applied on PS alpha value
|
||||
* dstFactorMode is actually applied on AS alpha value
|
||||
*/
|
||||
pxp_porter_duff_config_t pdConfig = {
|
||||
.enable = 1,
|
||||
.dstColorMode = kPXP_PorterDuffColorNoAlpha,
|
||||
.srcColorMode = kPXP_PorterDuffColorNoAlpha,
|
||||
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.dstFactorMode = kPXP_PorterDuffFactorStraight,
|
||||
.srcFactorMode = (opa >= (lv_opa_t)LV_OPA_MAX) ? kPXP_PorterDuffFactorStraight : kPXP_PorterDuffFactorInversed,
|
||||
.dstGlobalAlpha = opa,
|
||||
.srcGlobalAlpha = opa,
|
||||
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
|
||||
.srcAlphaMode = kPXP_PorterDuffAlphaStraight /*don't care*/
|
||||
};
|
||||
|
||||
PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
|
||||
|
||||
lv_gpu_nxp_pxp_run(); /*Start PXP task*/
|
||||
|
||||
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,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle)
|
||||
{
|
||||
uint32_t dest_size = lv_area_get_size(dest_area);
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
if(opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) {
|
||||
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) {
|
||||
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
|
||||
PXP_Init(LV_GPU_NXP_PXP_ID);
|
||||
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
|
||||
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
|
||||
|
||||
/* convert rotation angle */
|
||||
pxp_rotate_degree_t pxp_rot;
|
||||
switch(angle) {
|
||||
case LV_DISP_ROT_NONE:
|
||||
pxp_rot = kPXP_Rotate0;
|
||||
break;
|
||||
case LV_DISP_ROT_90:
|
||||
pxp_rot = kPXP_Rotate90;
|
||||
break;
|
||||
case LV_DISP_ROT_180:
|
||||
pxp_rot = kPXP_Rotate180;
|
||||
break;
|
||||
case LV_DISP_ROT_270:
|
||||
pxp_rot = kPXP_Rotate270;
|
||||
break;
|
||||
default:
|
||||
pxp_rot = kPXP_Rotate0;
|
||||
break;
|
||||
}
|
||||
PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable);
|
||||
|
||||
pxp_as_blend_config_t asBlendConfig = {
|
||||
.alpha = opa,
|
||||
.invertAlpha = false,
|
||||
.alphaMode = kPXP_AlphaRop,
|
||||
.ropMode = kPXP_RopMergeAs
|
||||
};
|
||||
|
||||
if(opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
/*Simple blit, no effect - Disable PS buffer*/
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
}
|
||||
else {
|
||||
pxp_ps_buffer_config_t psBufferConfig = {
|
||||
.pixelFormat = PXP_PS_PIXEL_FORMAT,
|
||||
.swapByte = false,
|
||||
.bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
|
||||
.bufferAddrU = 0U,
|
||||
.bufferAddrV = 0U,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t)
|
||||
};
|
||||
|
||||
asBlendConfig.alphaMode = kPXP_AlphaOverride;
|
||||
|
||||
PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1);
|
||||
}
|
||||
|
||||
lv_coord_t src_stride = lv_area_get_width(src_area);
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = PXP_AS_PIXEL_FORMAT,
|
||||
.bufferAddr = (uint32_t)src_buf,
|
||||
.pitchBytes = src_stride * sizeof(lv_color_t)
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
|
||||
PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
|
||||
PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false);
|
||||
|
||||
/*Output buffer.*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t),
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
|
||||
|
||||
lv_gpu_nxp_pxp_run(); /* Start PXP task */
|
||||
|
||||
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,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
|
||||
{
|
||||
uint32_t dest_size = lv_area_get_size(dest_area);
|
||||
|
||||
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) {
|
||||
PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
}
|
||||
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.*/
|
||||
return lv_gpu_nxp_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf);
|
||||
}
|
||||
|
||||
return lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
|
||||
{
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
lv_res_t res;
|
||||
uint32_t size = dest_w * dest_h * sizeof(lv_color_t);
|
||||
|
||||
if(ROUND_UP(size, ALIGN_SIZE) >= LV_MEM_SIZE)
|
||||
PXP_RETURN_INV("Insufficient memory for temporary buffer. Please increase LV_MEM_SIZE.");
|
||||
|
||||
lv_color_t * tmp_buf = (lv_color_t *)lv_mem_buf_get(size);
|
||||
if(!tmp_buf)
|
||||
PXP_RETURN_INV("Allocating temporary buffer failed.");
|
||||
|
||||
const lv_area_t tmp_area = {
|
||||
.x1 = 0,
|
||||
.y1 = 0,
|
||||
.x2 = dest_w - 1,
|
||||
.y2 = dest_h - 1
|
||||
};
|
||||
|
||||
/*Step 1: Transform with full opacity to temporary buffer*/
|
||||
res = lv_gpu_nxp_pxp_blit_cover(tmp_buf, &tmp_area, dest_w, src_buf, src_area, dsc, cf);
|
||||
if(res != LV_RES_OK) {
|
||||
PXP_LOG_TRACE("Blit cover with full opacity failed.");
|
||||
lv_mem_buf_release(tmp_buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*Step 2: Blit temporary results with required opacity to output*/
|
||||
res = lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, tmp_buf, &tmp_area, dsc, cf);
|
||||
|
||||
/*Clean-up memory*/
|
||||
lv_mem_buf_release(tmp_buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area,
|
||||
lv_coord_t dest_stride,
|
||||
const lv_color_t * src_buf, const lv_area_t * src_area,
|
||||
const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
|
||||
{
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
|
||||
bool rotation = (dsc->angle != 0);
|
||||
|
||||
PXP_Init(LV_GPU_NXP_PXP_ID);
|
||||
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
|
||||
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
|
||||
|
||||
if(rotation) {
|
||||
/*
|
||||
* PXP is set to process 16x16 blocks to optimize the system for memory
|
||||
* bandwidth and image processing time.
|
||||
* The output engine essentially truncates any output pixels after the
|
||||
* desired number of pixels has been written.
|
||||
* When rotating a source image and the output is not divisible by the block
|
||||
* size, the incorrect pixels could be truncated and the final output image
|
||||
* can look shifted.
|
||||
*/
|
||||
if(lv_area_get_width(src_area) % 16 || lv_area_get_height(src_area) % 16) {
|
||||
PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16.");
|
||||
return LV_RES_INV;
|
||||
}
|
||||
|
||||
/*Convert rotation angle*/
|
||||
pxp_rotate_degree_t pxp_rot;
|
||||
switch(dsc->angle) {
|
||||
case 0:
|
||||
pxp_rot = kPXP_Rotate0;
|
||||
break;
|
||||
case 900:
|
||||
pxp_rot = kPXP_Rotate90;
|
||||
break;
|
||||
case 1800:
|
||||
pxp_rot = kPXP_Rotate180;
|
||||
break;
|
||||
case 2700:
|
||||
pxp_rot = kPXP_Rotate270;
|
||||
break;
|
||||
default:
|
||||
PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle);
|
||||
return LV_RES_INV;
|
||||
}
|
||||
PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable);
|
||||
}
|
||||
|
||||
lv_coord_t src_stride = lv_area_get_width(src_area);
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = PXP_AS_PIXEL_FORMAT,
|
||||
.bufferAddr = (uint32_t)src_buf,
|
||||
.pitchBytes = src_stride * sizeof(lv_color_t)
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
|
||||
|
||||
/*Disable PS buffer*/
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
if(recolor)
|
||||
/*Use as color generator*/
|
||||
PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor));
|
||||
|
||||
/*Output buffer*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t),
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
|
||||
|
||||
if(recolor || lv_img_cf_has_alpha(cf)) {
|
||||
/**
|
||||
* Configure Porter-Duff blending.
|
||||
*
|
||||
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
|
||||
* srcFactorMode is actually applied on PS alpha value
|
||||
* dstFactorMode is actually applied on AS alpha value
|
||||
*/
|
||||
pxp_porter_duff_config_t pdConfig = {
|
||||
.enable = 1,
|
||||
.dstColorMode = kPXP_PorterDuffColorWithAlpha,
|
||||
.srcColorMode = kPXP_PorterDuffColorNoAlpha,
|
||||
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha,
|
||||
.dstFactorMode = kPXP_PorterDuffFactorStraight,
|
||||
.srcFactorMode = kPXP_PorterDuffFactorInversed,
|
||||
.dstGlobalAlpha = recolor ? dsc->recolor_opa : 0x00,
|
||||
.srcGlobalAlpha = 0xff,
|
||||
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
|
||||
.srcAlphaMode = kPXP_PorterDuffAlphaStraight
|
||||
};
|
||||
PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
|
||||
}
|
||||
|
||||
lv_gpu_nxp_pxp_run(); /*Start PXP task*/
|
||||
|
||||
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,
|
||||
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)
|
||||
{
|
||||
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
||||
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
PXP_Init(LV_GPU_NXP_PXP_ID);
|
||||
PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
|
||||
PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/
|
||||
|
||||
pxp_as_blend_config_t asBlendConfig = {
|
||||
.alpha = dsc->opa,
|
||||
.invertAlpha = false,
|
||||
.alphaMode = kPXP_AlphaRop,
|
||||
.ropMode = kPXP_RopMergeAs
|
||||
};
|
||||
|
||||
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_is_chroma_keyed(cf) && !lv_img_cf_has_alpha(cf)) {
|
||||
/*Simple blit, no effect - Disable PS buffer*/
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
}
|
||||
else {
|
||||
/*PS must be enabled to fetch background pixels.
|
||||
PS and OUT buffers are the same, blend will be done in-place*/
|
||||
pxp_ps_buffer_config_t psBufferConfig = {
|
||||
.pixelFormat = PXP_PS_PIXEL_FORMAT,
|
||||
.swapByte = false,
|
||||
.bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
|
||||
.bufferAddrU = 0U,
|
||||
.bufferAddrV = 0U,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t)
|
||||
};
|
||||
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaEmbedded : kPXP_AlphaOverride;
|
||||
}
|
||||
else {
|
||||
asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride;
|
||||
}
|
||||
PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
|
||||
PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1);
|
||||
}
|
||||
|
||||
lv_coord_t src_stride = lv_area_get_width(src_area);
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = PXP_AS_PIXEL_FORMAT,
|
||||
.bufferAddr = (uint32_t)src_buf,
|
||||
.pitchBytes = src_stride * sizeof(lv_color_t)
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
|
||||
PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
|
||||
|
||||
if(lv_img_cf_is_chroma_keyed(cf)) {
|
||||
lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY;
|
||||
lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY;
|
||||
|
||||
bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
|
||||
|
||||
if(recolor) {
|
||||
/* New color key after recoloring */
|
||||
lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa);
|
||||
|
||||
LV_COLOR_SET_R(colorKeyLow, colorKey.ch.red != 0 ? colorKey.ch.red - 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);
|
||||
|
||||
#if LV_COLOR_DEPTH==16
|
||||
LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f);
|
||||
LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f);
|
||||
LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f);
|
||||
#else /*LV_COLOR_DEPTH==32*/
|
||||
LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff);
|
||||
LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff);
|
||||
LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
PXP_SetAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, lv_color_to32(colorKeyLow),
|
||||
lv_color_to32(colorKeyHigh));
|
||||
}
|
||||
|
||||
PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, lv_img_cf_is_chroma_keyed(cf));
|
||||
|
||||
/*Output buffer.*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride * sizeof(lv_color_t),
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
|
||||
|
||||
lv_gpu_nxp_pxp_run(); /* Start PXP task */
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU_NXP_PXP*/
|
||||
Reference in New Issue
Block a user