1575 lines
70 KiB
C
1575 lines
70 KiB
C
/**
|
|
* @file lv_gpu_arm2d.c
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2010-2023 Arm Limited or its affiliates. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
|
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
|
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
|
|
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
|
#pragma clang diagnostic ignored "-Wcast-align"
|
|
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
|
|
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
#pragma clang diagnostic ignored "-Wunused-function"
|
|
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
#pragma clang diagnostic ignored "-Wimplicit-float-conversion"
|
|
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
|
|
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
|
#pragma clang diagnostic ignored "-Wsign-compare"
|
|
#pragma clang diagnostic ignored "-Wfloat-conversion"
|
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
|
#pragma clang diagnostic ignored "-Wpadded"
|
|
#pragma clang diagnostic ignored "-Wundef"
|
|
#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
|
|
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
|
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
|
#pragma clang diagnostic ignored "-Wint-conversion"
|
|
#endif
|
|
|
|
|
|
#include "lv_gpu_arm2d.h"
|
|
#include "../../core/lv_refr.h"
|
|
|
|
#if LV_USE_GPU_ARM2D
|
|
#define __ARM_2D_IMPL__
|
|
#include "arm_2d.h"
|
|
#include "__arm_2d_impl.h"
|
|
|
|
|
|
#if defined(__IS_COMPILER_ARM_COMPILER_5__)
|
|
#pragma diag_suppress 174,177,188,68,513,144,1296
|
|
#elif defined(__IS_COMPILER_IAR__)
|
|
#pragma diag_suppress=Pa093
|
|
#elif defined(__IS_COMPILER_GCC__)
|
|
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
|
|
#endif
|
|
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
#if ( !defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) \
|
|
|| !__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) \
|
|
&& LV_COLOR_DEPTH == 32 \
|
|
&& !defined(__ARM_2D_LVGL_CFG_NO_WARNING__)
|
|
#warning Please set macro __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__ to 1 to get more acceleration opportunities. Or you can define macro __ARM_2D_LVGL_CFG_NO_WARNING__ to suppress this warning.
|
|
#endif
|
|
|
|
#define MAX_BUF_SIZE (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
|
|
|
|
#if LV_COLOR_DEPTH == 16
|
|
#define arm_2d_fill_colour arm_2d_rgb16_fill_colour
|
|
#define arm_2d_fill_colour_with_alpha arm_2d_rgb565_fill_colour_with_alpha
|
|
#define arm_2d_fill_colour_with_mask arm_2d_rgb565_fill_colour_with_mask
|
|
#define arm_2d_fill_colour_with_mask_and_opacity \
|
|
arm_2d_rgb565_fill_colour_with_mask_and_opacity
|
|
#define arm_2d_tile_copy arm_2d_rgb16_tile_copy
|
|
#define arm_2d_alpha_blending arm_2d_rgb565_alpha_blending
|
|
#define arm_2d_tile_copy_with_src_mask arm_2d_rgb565_tile_copy_with_src_mask
|
|
#define arm_2d_color_t arm_2d_color_rgb565_t
|
|
|
|
/* arm-2d direct mode apis */
|
|
#define __arm_2d_impl_colour_filling __arm_2d_impl_rgb16_colour_filling
|
|
#define __arm_2d_impl_colour_filling_with_opacity \
|
|
__arm_2d_impl_rgb565_colour_filling_with_opacity
|
|
#define __arm_2d_impl_colour_filling_mask \
|
|
__arm_2d_impl_rgb565_colour_filling_mask
|
|
#define __arm_2d_impl_colour_filling_mask_opacity \
|
|
__arm_2d_impl_rgb565_colour_filling_mask_opacity
|
|
#define __arm_2d_impl_copy __arm_2d_impl_rgb16_copy
|
|
#define __arm_2d_impl_alpha_blending __arm_2d_impl_rgb565_alpha_blending
|
|
#define __arm_2d_impl_src_msk_copy __arm_2d_impl_rgb565_src_msk_copy
|
|
#define __arm_2d_impl_src_chn_msk_copy __arm_2d_impl_rgb565_src_chn_msk_copy
|
|
#define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb16_cl_key_copy
|
|
#define __arm_2d_impl_alpha_blending_colour_keying \
|
|
__arm_2d_impl_rgb565_alpha_blending_colour_keying
|
|
#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \
|
|
arm_2dp_rgb565_tile_transform_with_src_mask_and_opacity_prepare
|
|
#define arm_2d_tile_transform_with_opacity_prepare \
|
|
arm_2dp_rgb565_tile_transform_with_opacity_prepare
|
|
#define arm_2d_tile_transform_only_with_opacity_prepare \
|
|
arm_2dp_rgb565_tile_transform_only_with_opacity_prepare
|
|
#define arm_2d_tile_transform_prepare \
|
|
arm_2dp_rgb565_tile_transform_prepare
|
|
|
|
#define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_RGB565
|
|
|
|
#define color_int uint16_t
|
|
|
|
#elif LV_COLOR_DEPTH == 32
|
|
#define arm_2d_fill_colour arm_2d_rgb32_fill_colour
|
|
#define arm_2d_fill_colour_with_alpha arm_2d_cccn888_fill_colour_with_alpha
|
|
#define arm_2d_fill_colour_with_mask arm_2d_cccn888_fill_colour_with_mask
|
|
#define arm_2d_fill_colour_with_mask_and_opacity \
|
|
arm_2d_cccn888_fill_colour_with_mask_and_opacity
|
|
#define arm_2d_tile_copy arm_2d_rgb32_tile_copy
|
|
#define arm_2d_alpha_blending arm_2d_cccn888_alpha_blending
|
|
#define arm_2d_tile_copy_with_src_mask arm_2d_cccn888_tile_copy_with_src_mask
|
|
#define arm_2d_color_t arm_2d_color_cccn888_t
|
|
|
|
/* arm-2d direct mode apis */
|
|
#define __arm_2d_impl_colour_filling __arm_2d_impl_rgb32_colour_filling
|
|
#define __arm_2d_impl_colour_filling_with_opacity \
|
|
__arm_2d_impl_cccn888_colour_filling_with_opacity
|
|
#define __arm_2d_impl_colour_filling_mask \
|
|
__arm_2d_impl_cccn888_colour_filling_mask
|
|
#define __arm_2d_impl_colour_filling_mask_opacity \
|
|
__arm_2d_impl_cccn888_colour_filling_mask_opacity
|
|
#define __arm_2d_impl_copy __arm_2d_impl_rgb32_copy
|
|
#define __arm_2d_impl_alpha_blending __arm_2d_impl_cccn888_alpha_blending
|
|
#define __arm_2d_impl_src_msk_copy __arm_2d_impl_cccn888_src_msk_copy
|
|
#define __arm_2d_impl_src_chn_msk_copy __arm_2d_impl_cccn888_src_chn_msk_copy
|
|
#define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb32_cl_key_copy
|
|
#define __arm_2d_impl_alpha_blending_colour_keying \
|
|
__arm_2d_impl_cccn888_alpha_blending_colour_keying
|
|
#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \
|
|
arm_2dp_cccn888_tile_transform_with_src_mask_and_opacity_prepare
|
|
#define arm_2d_tile_transform_with_opacity_prepare \
|
|
arm_2dp_cccn888_tile_transform_with_opacity_prepare
|
|
#define arm_2d_tile_transform_only_with_opacity_prepare \
|
|
arm_2dp_cccn888_tile_transform_only_with_opacity_prepare
|
|
#define arm_2d_tile_transform_prepare \
|
|
arm_2dp_cccn888_tile_transform_prepare
|
|
|
|
#define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_CCCN888
|
|
|
|
#define color_int uint32_t
|
|
|
|
#else
|
|
#error The specified LV_COLOR_DEPTH is not supported by this version of lv_gpu_arm2d.c.
|
|
#endif
|
|
|
|
/* *INDENT-OFF* */
|
|
#define __PREPARE_LL_ACCELERATION__() \
|
|
int32_t src_stride = lv_area_get_width(coords); \
|
|
\
|
|
uint8_t px_size_byte = cf == LV_IMG_CF_TRUE_COLOR_ALPHA \
|
|
? LV_IMG_PX_SIZE_ALPHA_BYTE \
|
|
: sizeof(lv_color_t); \
|
|
\
|
|
const uint8_t * src_buf_tmp = src_buf; \
|
|
src_buf_tmp += src_stride \
|
|
* (draw_area.y1 - coords->y1) \
|
|
* px_size_byte; \
|
|
src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte; \
|
|
\
|
|
lv_area_t blend_area2; \
|
|
if(!_lv_area_intersect(&blend_area2, \
|
|
&draw_area, \
|
|
draw_ctx->clip_area)) return; \
|
|
\
|
|
int32_t w = lv_area_get_width(&blend_area2); \
|
|
int32_t h = lv_area_get_height(&blend_area2); \
|
|
\
|
|
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); \
|
|
\
|
|
lv_color_t * dest_buf = draw_ctx->buf; \
|
|
dest_buf += dest_stride * (blend_area2.y1 - draw_ctx->buf_area->y1) \
|
|
+ (blend_area2.x1 - draw_ctx->buf_area->x1); \
|
|
\
|
|
arm_2d_size_t copy_size = { \
|
|
.iWidth = lv_area_get_width(&blend_area2), \
|
|
.iHeight = lv_area_get_height(&blend_area2), \
|
|
}
|
|
|
|
#define __PREPARE_TARGET_TILE__(__blend_area) \
|
|
static arm_2d_tile_t target_tile; \
|
|
static arm_2d_region_t target_region; \
|
|
\
|
|
lv_color_t * dest_buf = draw_ctx->buf; \
|
|
\
|
|
target_tile = (arm_2d_tile_t) { \
|
|
.tRegion = { \
|
|
.tSize = { \
|
|
.iWidth = lv_area_get_width(draw_ctx->buf_area), \
|
|
.iHeight = lv_area_get_height(draw_ctx->buf_area), \
|
|
}, \
|
|
}, \
|
|
.tInfo.bIsRoot = true, \
|
|
.phwBuffer = (uint16_t *)draw_ctx->buf, \
|
|
}; \
|
|
\
|
|
target_region = (arm_2d_region_t) { \
|
|
.tLocation = { \
|
|
.iX = (__blend_area).x1 - draw_ctx->buf_area->x1, \
|
|
.iY = (__blend_area).y1 - draw_ctx->buf_area->y1, \
|
|
}, \
|
|
.tSize = { \
|
|
.iWidth = lv_area_get_width(&(__blend_area)), \
|
|
.iHeight = lv_area_get_height(&(__blend_area)), \
|
|
}, \
|
|
}
|
|
|
|
#define __PREPARE_SOURCE_TILE__(__dsc, __blend_area) \
|
|
static arm_2d_tile_t source_tile_orig; \
|
|
static arm_2d_tile_t source_tile; \
|
|
const lv_color_t * src_buf = (__dsc)->src_buf; \
|
|
if (src_buf) { \
|
|
source_tile_orig = (arm_2d_tile_t) { \
|
|
.tRegion = { \
|
|
.tSize = { \
|
|
.iWidth = lv_area_get_width((__dsc)->blend_area), \
|
|
.iHeight = lv_area_get_height((__dsc)->blend_area), \
|
|
}, \
|
|
}, \
|
|
.tInfo.bIsRoot = true, \
|
|
.phwBuffer = (uint16_t *)src_buf, \
|
|
}; \
|
|
\
|
|
arm_2d_tile_generate_child( \
|
|
&source_tile_orig, \
|
|
(arm_2d_region_t []) { \
|
|
{ \
|
|
.tLocation = { \
|
|
.iX = (__blend_area).x1 - (__dsc)->blend_area->x1, \
|
|
.iY = (__blend_area).y1 - (__dsc)->blend_area->y1, \
|
|
}, \
|
|
.tSize = source_tile_orig.tRegion.tSize, \
|
|
} \
|
|
}, \
|
|
&source_tile, \
|
|
false); \
|
|
source_tile.tInfo.bDerivedResource = true; \
|
|
}
|
|
|
|
#define __PREPARE_MASK_TILE__(__dsc, __blend_area, __mask, __is_chn) \
|
|
static arm_2d_tile_t mask_tile_orig; \
|
|
static arm_2d_tile_t mask_tile; \
|
|
if(NULL != (__mask)) { \
|
|
mask_tile_orig = (arm_2d_tile_t) { \
|
|
.tRegion = { \
|
|
.tSize = { \
|
|
.iWidth = lv_area_get_width((__dsc)->mask_area), \
|
|
.iHeight = lv_area_get_height((__dsc)->mask_area), \
|
|
}, \
|
|
}, \
|
|
.tInfo = { \
|
|
.bIsRoot = true, \
|
|
.bHasEnforcedColour = true, \
|
|
.tColourInfo = { \
|
|
.chScheme = (__is_chn) ? ARM_2D_CHANNEL_8in32 \
|
|
: ARM_2D_COLOUR_8BIT, \
|
|
}, \
|
|
}, \
|
|
.pchBuffer = ((uint8_t *)(__mask)) + (__is_chn) ? 3 : 0, \
|
|
}; \
|
|
\
|
|
arm_2d_tile_generate_child( \
|
|
&mask_tile_orig, \
|
|
(arm_2d_region_t []) { \
|
|
{ \
|
|
.tLocation = { \
|
|
.iX = (__dsc)->mask_area->x1 - (__blend_area).x1, \
|
|
.iY = (__dsc)->mask_area->y1 - (__blend_area).y1, \
|
|
}, \
|
|
.tSize = mask_tile_orig.tRegion.tSize, \
|
|
} \
|
|
}, \
|
|
&mask_tile, \
|
|
false); \
|
|
mask_tile.tInfo.bDerivedResource = true; \
|
|
}
|
|
/* *INDENT-ON* */
|
|
|
|
/* *INDENT-OFF* */
|
|
#define __RECOLOUR_WRAPPER(...) \
|
|
do { \
|
|
lv_color_t *rgb_tmp_buf = NULL; \
|
|
if(draw_dsc->recolor_opa > LV_OPA_MIN) { \
|
|
rgb_tmp_buf \
|
|
= lv_mem_buf_get(src_w * src_h * sizeof(lv_color_t)); \
|
|
if (NULL == rgb_tmp_buf) { \
|
|
LV_LOG_WARN( \
|
|
"Failed to allocate memory for accelerating recolour, " \
|
|
"use normal route instead."); \
|
|
break; \
|
|
} \
|
|
lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\
|
|
arm_2d_size_t copy_size = { \
|
|
.iWidth = src_w, \
|
|
.iHeight = src_h, \
|
|
}; \
|
|
/* apply re-colour */ \
|
|
__arm_2d_impl_colour_filling_with_opacity( \
|
|
(color_int *)rgb_tmp_buf, \
|
|
src_w, \
|
|
©_size, \
|
|
(color_int)draw_dsc->recolor.full, \
|
|
draw_dsc->recolor_opa); \
|
|
\
|
|
/* replace src_buf for the following operation */ \
|
|
src_buf = (const uint8_t *)rgb_tmp_buf; \
|
|
} \
|
|
do { \
|
|
__VA_ARGS__ \
|
|
} while(0); \
|
|
if (NULL != rgb_tmp_buf) { \
|
|
lv_mem_buf_release(rgb_tmp_buf); \
|
|
} \
|
|
} while(0); \
|
|
src_buf = src_buf_org;
|
|
|
|
#define __RECOLOUR_BEGIN() \
|
|
do { \
|
|
lv_color_t *rgb_tmp_buf = NULL; \
|
|
if(draw_dsc->recolor_opa > LV_OPA_MIN) { \
|
|
rgb_tmp_buf \
|
|
= lv_mem_buf_get(src_w * src_h * sizeof(lv_color_t)); \
|
|
if (NULL == rgb_tmp_buf) { \
|
|
LV_LOG_WARN( \
|
|
"Failed to allocate memory for accelerating recolour, " \
|
|
"use normal route instead."); \
|
|
break; \
|
|
} \
|
|
lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\
|
|
arm_2d_size_t copy_size = { \
|
|
.iWidth = src_w, \
|
|
.iHeight = src_h, \
|
|
}; \
|
|
/* apply re-colour */ \
|
|
__arm_2d_impl_colour_filling_with_opacity( \
|
|
(color_int *)rgb_tmp_buf, \
|
|
src_w, \
|
|
©_size, \
|
|
(color_int)draw_dsc->recolor.full, \
|
|
draw_dsc->recolor_opa); \
|
|
\
|
|
/* replace src_buf for the following operation */ \
|
|
src_buf = (const uint8_t *)rgb_tmp_buf; \
|
|
} \
|
|
do {
|
|
|
|
#define __RECOLOUR_END() \
|
|
} while(0); \
|
|
if (NULL != rgb_tmp_buf) { \
|
|
lv_mem_buf_release(rgb_tmp_buf); \
|
|
} \
|
|
} while(0); \
|
|
src_buf = src_buf_org;
|
|
|
|
#define __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(__TRANS_PREPARE, ...) \
|
|
do { \
|
|
__TRANS_PREPARE( \
|
|
NULL, \
|
|
__VA_ARGS__); \
|
|
\
|
|
target_region = (arm_2d_region_t) { \
|
|
.tLocation = { \
|
|
.iX = coords->x1 - draw_ctx->clip_area->x1, \
|
|
.iY = coords->y1 - draw_ctx->clip_area->y1, \
|
|
}, \
|
|
.tSize = { \
|
|
.iWidth = lv_area_get_width(coords), \
|
|
.iHeight = lv_area_get_height(coords), \
|
|
}, \
|
|
}; \
|
|
\
|
|
arm_2d_size_t tTransSize \
|
|
= ARM_2D_CTRL.DefaultOP \
|
|
.tTransform.Source.ptTile->tRegion.tSize; \
|
|
\
|
|
if (target_region.tSize.iWidth < tTransSize.iWidth) { \
|
|
int16_t iDelta = tTransSize.iWidth - target_region.tSize.iWidth;\
|
|
target_region.tLocation.iX -= iDelta / 2; \
|
|
target_region.tSize.iWidth = tTransSize.iWidth; \
|
|
} \
|
|
\
|
|
if (target_region.tSize.iHeight < tTransSize.iHeight) { \
|
|
int16_t iDelta \
|
|
= tTransSize.iHeight - target_region.tSize.iHeight; \
|
|
target_region.tLocation.iY -= iDelta / 2; \
|
|
target_region.tSize.iHeight = tTransSize.iHeight; \
|
|
} \
|
|
} while(0)
|
|
|
|
/* *INDENT-ON* */
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
|
|
#if __ARM_2D_HAS_HW_ACC__
|
|
static bool /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_fill_colour(const arm_2d_tile_t * target_tile,
|
|
const arm_2d_region_t * region,
|
|
lv_color_t color,
|
|
lv_opa_t opa,
|
|
const arm_2d_tile_t * mask_tile);
|
|
|
|
static bool /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_tile_copy(const arm_2d_tile_t * target_tile,
|
|
const arm_2d_region_t * region,
|
|
arm_2d_tile_t * source_tile,
|
|
lv_opa_t opa,
|
|
arm_2d_tile_t * mask_tile);
|
|
#else
|
|
|
|
static void convert_cb(const lv_area_t * dest_area,
|
|
const void * src_buf,
|
|
lv_coord_t src_w,
|
|
lv_coord_t src_h,
|
|
lv_coord_t src_stride,
|
|
const lv_draw_img_dsc_t * draw_dsc,
|
|
lv_img_cf_t cf,
|
|
lv_color_t * cbuf,
|
|
lv_opa_t * abuf);
|
|
|
|
static bool /* LV_ATTRIBUTE_FAST_MEM */ arm_2d_fill_normal(lv_color_t * dest_buf,
|
|
const lv_area_t * dest_area,
|
|
lv_coord_t dest_stride,
|
|
lv_color_t color,
|
|
lv_opa_t opa,
|
|
const lv_opa_t * mask,
|
|
lv_coord_t mask_stride);
|
|
|
|
static bool /* LV_ATTRIBUTE_FAST_MEM */ arm_2d_copy_normal(lv_color_t * dest_buf,
|
|
const lv_area_t * dest_area,
|
|
lv_coord_t dest_stride,
|
|
const lv_color_t * src_buf,
|
|
lv_coord_t src_stride,
|
|
lv_opa_t opa,
|
|
const lv_opa_t * mask,
|
|
lv_coord_t mask_stride);
|
|
#endif
|
|
|
|
static void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
|
|
const lv_draw_sw_blend_dsc_t * dsc);
|
|
static void /* LV_ATTRIBUTE_FAST_MEM */ lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx);
|
|
static void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx,
|
|
const lv_draw_img_dsc_t * draw_dsc,
|
|
const lv_area_t * coords,
|
|
const uint8_t * src_buf,
|
|
lv_img_cf_t cf);
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
|
|
void lv_draw_arm2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
|
|
{
|
|
arm_2d_init();
|
|
|
|
lv_draw_sw_init_ctx(drv, draw_ctx);
|
|
|
|
lv_draw_arm2d_ctx_t * arm2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
|
|
|
|
arm2d_draw_ctx->blend = lv_draw_arm2d_blend;
|
|
arm2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_arm2d_wait_cb;
|
|
|
|
#if !__ARM_2D_HAS_HW_ACC__
|
|
arm2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_arm2d_img_decoded;
|
|
#endif
|
|
|
|
}
|
|
|
|
void lv_draw_arm2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
|
|
{
|
|
LV_UNUSED(drv);
|
|
LV_UNUSED(draw_ctx);
|
|
}
|
|
|
|
extern void test_flush(lv_color_t * color_p);
|
|
|
|
#if __ARM_2D_HAS_HW_ACC__
|
|
static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
|
|
const lv_draw_sw_blend_dsc_t * dsc)
|
|
{
|
|
const lv_opa_t * mask;
|
|
if(dsc->mask_buf == NULL) mask = NULL;
|
|
if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
|
|
else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
|
|
else mask = dsc->mask_buf;
|
|
|
|
|
|
lv_area_t blend_area;
|
|
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) {
|
|
return;
|
|
}
|
|
|
|
bool is_accelerated = false;
|
|
|
|
if(dsc->blend_mode == LV_BLEND_MODE_NORMAL
|
|
&& lv_area_get_size(&blend_area) > 100) {
|
|
|
|
__PREPARE_TARGET_TILE__(blend_area);
|
|
__PREPARE_SOURCE_TILE__(dsc, blend_area);
|
|
__PREPARE_MASK_TILE__(dsc, blend_area, mask, false);
|
|
|
|
if(src_buf) {
|
|
is_accelerated = lv_draw_arm2d_tile_copy(
|
|
&target_tile,
|
|
&target_region,
|
|
&source_tile,
|
|
dsc->opa,
|
|
(NULL == mask) ? NULL : &mask_tile);
|
|
}
|
|
else {
|
|
is_accelerated = lv_draw_arm2d_fill_colour(
|
|
&target_tile,
|
|
&target_region,
|
|
dsc->color,
|
|
dsc->opa,
|
|
(NULL == mask) ? NULL : &mask_tile);
|
|
}
|
|
}
|
|
|
|
if(!is_accelerated) {
|
|
lv_draw_sw_blend_basic(draw_ctx, dsc);
|
|
}
|
|
}
|
|
|
|
|
|
static bool LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_fill_colour(const arm_2d_tile_t * target_tile,
|
|
const arm_2d_region_t * region,
|
|
lv_color_t color,
|
|
lv_opa_t opa,
|
|
const arm_2d_tile_t * mask_tile)
|
|
{
|
|
arm_fsm_rt_t result = (arm_fsm_rt_t)ARM_2D_ERR_NONE;
|
|
|
|
if(NULL == mask_tile) {
|
|
if(opa >= LV_OPA_MAX) {
|
|
result = arm_2d_fill_colour(target_tile, region, color.full);
|
|
}
|
|
else {
|
|
#if LV_COLOR_SCREEN_TRANSP
|
|
return false;
|
|
#else
|
|
result = arm_2d_fill_colour_with_alpha(
|
|
target_tile,
|
|
region,
|
|
(arm_2d_color_t) {
|
|
color.full
|
|
},
|
|
opa);
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
|
|
if(opa >= LV_OPA_MAX) {
|
|
result = arm_2d_fill_colour_with_mask(
|
|
target_tile,
|
|
region,
|
|
mask_tile,
|
|
(arm_2d_color_t) {
|
|
color.full
|
|
});
|
|
}
|
|
else {
|
|
#if LV_COLOR_SCREEN_TRANSP
|
|
return false;
|
|
#else
|
|
result = arm_2d_fill_colour_with_mask_and_opacity(
|
|
target_tile,
|
|
region,
|
|
mask_tile,
|
|
(arm_2d_color_t) {
|
|
color.full
|
|
},
|
|
opa);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if(result < 0) {
|
|
/* error detected */
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static bool LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_tile_copy(const arm_2d_tile_t * target_tile,
|
|
const arm_2d_region_t * region,
|
|
arm_2d_tile_t * source_tile,
|
|
lv_opa_t opa,
|
|
arm_2d_tile_t * mask_tile)
|
|
{
|
|
arm_fsm_rt_t result = (arm_fsm_rt_t)ARM_2D_ERR_NONE;
|
|
|
|
if(NULL == mask_tile) {
|
|
if(opa >= LV_OPA_MAX) {
|
|
result = arm_2d_tile_copy(source_tile,
|
|
target_tile,
|
|
region,
|
|
ARM_2D_CP_MODE_COPY);
|
|
}
|
|
#if LV_COLOR_SCREEN_TRANSP
|
|
else {
|
|
return false; /* not supported */
|
|
}
|
|
#else
|
|
else {
|
|
result = arm_2d_alpha_blending(source_tile,
|
|
target_tile,
|
|
region,
|
|
opa);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if LV_COLOR_SCREEN_TRANSP
|
|
return false; /* not support */
|
|
#else
|
|
|
|
if(opa >= LV_OPA_MAX) {
|
|
result = arm_2d_tile_copy_with_src_mask(source_tile,
|
|
mask_tile,
|
|
target_tile,
|
|
region,
|
|
ARM_2D_CP_MODE_COPY);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(result < 0) {
|
|
/* error detected */
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)
|
|
{
|
|
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
|
|
|
arm_2d_op_wait_async(NULL);
|
|
if(disp->driver && disp->driver->wait_cb) {
|
|
disp->driver->wait_cb(disp->driver);
|
|
}
|
|
lv_draw_sw_wait_for_finish(draw_ctx);
|
|
}
|
|
#else
|
|
|
|
|
|
static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
|
|
const lv_draw_sw_blend_dsc_t * dsc)
|
|
{
|
|
const lv_opa_t * mask;
|
|
if(dsc->mask_buf == NULL) mask = NULL;
|
|
if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
|
|
else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
|
|
else mask = dsc->mask_buf;
|
|
|
|
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
|
|
|
lv_area_t blend_area;
|
|
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
|
|
|
|
//lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
|
|
|
bool is_accelerated = false;
|
|
do {
|
|
|
|
/* target buffer */
|
|
lv_color_t * dest_buf = draw_ctx->buf;
|
|
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
|
if(disp->driver->screen_transp == 0) {
|
|
dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
|
|
}
|
|
else {
|
|
/*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/
|
|
uint8_t * dest_buf8 = (uint8_t *) dest_buf;
|
|
dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
|
dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
|
dest_buf = (lv_color_t *)dest_buf8;
|
|
}
|
|
|
|
/* source buffer */
|
|
const lv_color_t * src_buf = dsc->src_buf;
|
|
lv_coord_t src_stride;
|
|
if(src_buf) {
|
|
src_stride = lv_area_get_width(dsc->blend_area);
|
|
src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
|
|
}
|
|
else {
|
|
src_stride = 0;
|
|
}
|
|
|
|
lv_coord_t mask_stride;
|
|
if(mask) {
|
|
mask_stride = lv_area_get_width(dsc->mask_area);
|
|
mask += mask_stride * (blend_area.y1 - dsc->mask_area->y1) + (blend_area.x1 - dsc->mask_area->x1);
|
|
}
|
|
else {
|
|
mask_stride = 0;
|
|
}
|
|
|
|
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
|
|
|
|
if(disp->driver->screen_transp) {
|
|
break;
|
|
}
|
|
if(dsc->src_buf == NULL) {
|
|
if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
|
is_accelerated = arm_2d_fill_normal(dest_buf,
|
|
&blend_area,
|
|
dest_stride,
|
|
dsc->color,
|
|
dsc->opa,
|
|
mask,
|
|
mask_stride);
|
|
}
|
|
}
|
|
else {
|
|
if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
|
is_accelerated = arm_2d_copy_normal(dest_buf,
|
|
&blend_area,
|
|
dest_stride,
|
|
src_buf,
|
|
src_stride,
|
|
dsc->opa,
|
|
mask,
|
|
mask_stride);
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if(!is_accelerated) lv_draw_sw_blend_basic(draw_ctx, dsc);
|
|
}
|
|
|
|
static bool LV_ATTRIBUTE_FAST_MEM arm_2d_fill_normal(lv_color_t * dest_buf,
|
|
const lv_area_t * dest_area,
|
|
lv_coord_t dest_stride,
|
|
lv_color_t color,
|
|
lv_opa_t opa,
|
|
const lv_opa_t * mask,
|
|
lv_coord_t mask_stride)
|
|
{
|
|
arm_2d_size_t target_size = {
|
|
.iWidth = lv_area_get_width(dest_area),
|
|
.iHeight = lv_area_get_height(dest_area),
|
|
};
|
|
|
|
/*No mask*/
|
|
if(mask == NULL) {
|
|
if(opa >= LV_OPA_MAX) {
|
|
__arm_2d_impl_colour_filling((color_int *)dest_buf,
|
|
dest_stride,
|
|
&target_size,
|
|
color.full);
|
|
}
|
|
/*Has opacity*/
|
|
else {
|
|
__arm_2d_impl_colour_filling_with_opacity((color_int *)dest_buf,
|
|
dest_stride,
|
|
&target_size,
|
|
color.full,
|
|
opa);
|
|
}
|
|
}
|
|
/*Masked*/
|
|
else {
|
|
/*Only the mask matters*/
|
|
if(opa >= LV_OPA_MAX) {
|
|
__arm_2d_impl_colour_filling_mask((color_int *)dest_buf,
|
|
dest_stride,
|
|
(uint8_t *)mask,
|
|
mask_stride,
|
|
&target_size,
|
|
color.full);
|
|
}
|
|
/*With opacity*/
|
|
else {
|
|
__arm_2d_impl_colour_filling_mask_opacity((color_int *)dest_buf,
|
|
dest_stride,
|
|
(uint8_t *)mask,
|
|
mask_stride,
|
|
&target_size,
|
|
color.full,
|
|
opa);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool LV_ATTRIBUTE_FAST_MEM arm_2d_copy_normal(lv_color_t * dest_buf,
|
|
const lv_area_t * dest_area,
|
|
lv_coord_t dest_stride,
|
|
const lv_color_t * src_buf,
|
|
lv_coord_t src_stride,
|
|
lv_opa_t opa,
|
|
const lv_opa_t * mask,
|
|
lv_coord_t mask_stride)
|
|
|
|
{
|
|
int32_t w = lv_area_get_width(dest_area);
|
|
int32_t h = lv_area_get_height(dest_area);
|
|
|
|
arm_2d_size_t copy_size = {
|
|
.iWidth = lv_area_get_width(dest_area),
|
|
.iHeight = lv_area_get_height(dest_area),
|
|
};
|
|
|
|
/*Simple fill (maybe with opacity), no masking*/
|
|
if(mask == NULL) {
|
|
if(opa >= LV_OPA_MAX) {
|
|
__arm_2d_impl_copy((color_int *)src_buf,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
else {
|
|
__arm_2d_impl_alpha_blending((color_int *)src_buf,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size,
|
|
opa);
|
|
}
|
|
}
|
|
/*Masked*/
|
|
else {
|
|
/*Only the mask matters*/
|
|
if(opa > LV_OPA_MAX) {
|
|
__arm_2d_impl_src_msk_copy((color_int *)src_buf,
|
|
src_stride,
|
|
(uint8_t *)mask,
|
|
mask_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
/*Handle opa and mask values too*/
|
|
else {
|
|
__arm_2d_impl_gray8_alpha_blending((uint8_t *)mask,
|
|
mask_stride,
|
|
(uint8_t *)mask,
|
|
mask_stride,
|
|
©_size,
|
|
opa);
|
|
|
|
__arm_2d_impl_src_msk_copy((color_int *)src_buf,
|
|
src_stride,
|
|
(uint8_t *)mask,
|
|
mask_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx,
|
|
const lv_draw_img_dsc_t * draw_dsc,
|
|
const lv_area_t * coords,
|
|
const uint8_t * src_buf,
|
|
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);
|
|
const uint8_t * src_buf_org = src_buf;
|
|
|
|
bool mask_any = lv_draw_mask_is_any(&draw_area);
|
|
bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
|
|
|
|
lv_area_t blend_area;
|
|
lv_draw_sw_blend_dsc_t blend_dsc;
|
|
|
|
lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
|
|
blend_dsc.opa = draw_dsc->opa;
|
|
blend_dsc.blend_mode = draw_dsc->blend_mode;
|
|
blend_dsc.blend_area = &blend_area;
|
|
|
|
if(lv_img_cf_is_chroma_keyed(cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
|
|
else if(cf == LV_IMG_CF_ALPHA_8BIT) {}
|
|
else if(cf == LV_IMG_CF_RGB565A8) {}
|
|
else if(lv_img_cf_has_alpha(cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
|
|
else cf = LV_IMG_CF_TRUE_COLOR;
|
|
|
|
|
|
/*The simplest case just copy the pixels into the draw_buf*/
|
|
if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
|
|
blend_dsc.src_buf = (const lv_color_t *)src_buf;
|
|
|
|
blend_dsc.blend_area = coords;
|
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
|
}
|
|
else if(!mask_any && !transform && cf == LV_IMG_CF_ALPHA_8BIT) {
|
|
lv_area_t clipped_coords;
|
|
if(!_lv_area_intersect(&clipped_coords, coords, draw_ctx->clip_area)) return;
|
|
|
|
blend_dsc.mask_buf = (lv_opa_t *)src_buf;
|
|
blend_dsc.mask_area = coords;
|
|
blend_dsc.src_buf = NULL;
|
|
blend_dsc.color = draw_dsc->recolor;
|
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
|
|
|
blend_dsc.blend_area = coords;
|
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
|
}
|
|
#if LV_COLOR_DEPTH == 16
|
|
else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP &&
|
|
blend_dsc.opa >= LV_OPA_MAX) {
|
|
lv_coord_t src_w = lv_area_get_width(coords);
|
|
lv_coord_t src_h = lv_area_get_height(coords);
|
|
blend_dsc.src_buf = (const lv_color_t *)src_buf;
|
|
blend_dsc.mask_buf = (lv_opa_t *)src_buf;
|
|
blend_dsc.mask_buf += sizeof(lv_color_t) * src_w * src_h;
|
|
blend_dsc.blend_area = coords;
|
|
blend_dsc.mask_area = coords;
|
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
|
}
|
|
#endif
|
|
/*In the other cases every pixel need to be checked one-by-one*/
|
|
else {
|
|
blend_area.x1 = draw_ctx->clip_area->x1;
|
|
blend_area.x2 = draw_ctx->clip_area->x2;
|
|
blend_area.y1 = draw_ctx->clip_area->y1;
|
|
blend_area.y2 = draw_ctx->clip_area->y2;
|
|
|
|
lv_coord_t src_w = lv_area_get_width(coords);
|
|
lv_coord_t src_h = lv_area_get_height(coords);
|
|
lv_coord_t blend_h = lv_area_get_height(&blend_area);
|
|
lv_coord_t blend_w = lv_area_get_width(&blend_area);
|
|
|
|
uint32_t max_buf_size = MAX_BUF_SIZE;
|
|
uint32_t blend_size = lv_area_get_size(&blend_area);
|
|
uint32_t buf_h;
|
|
uint32_t buf_w = blend_w;
|
|
if(blend_size <= max_buf_size) {
|
|
buf_h = blend_h;
|
|
}
|
|
else {
|
|
/*Round to full lines*/
|
|
buf_h = max_buf_size / blend_w;
|
|
}
|
|
|
|
/*Create buffers and masks*/
|
|
uint32_t buf_size = buf_w * buf_h;
|
|
|
|
lv_color_t * rgb_buf = lv_mem_buf_get(buf_size * sizeof(lv_color_t));
|
|
lv_opa_t * mask_buf = lv_mem_buf_get(buf_size);
|
|
blend_dsc.mask_buf = mask_buf;
|
|
blend_dsc.mask_area = &blend_area;
|
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
|
blend_dsc.src_buf = rgb_buf;
|
|
lv_coord_t y_last = blend_area.y2;
|
|
blend_area.y2 = blend_area.y1 + buf_h - 1;
|
|
|
|
lv_draw_mask_res_t mask_res_def = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
|
|
draw_dsc->zoom != LV_IMG_ZOOM_NONE) ?
|
|
LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
|
blend_dsc.mask_res = mask_res_def;
|
|
|
|
if(cf == LV_IMG_CF_ALPHA_8BIT) {
|
|
/* original code:
|
|
lv_color_fill(rgb_buf, draw_dsc->recolor, buf_size);
|
|
*/
|
|
arm_2d_size_t copy_size = {
|
|
.iWidth = buf_w,
|
|
.iHeight = buf_h,
|
|
};
|
|
|
|
/* apply re-colour */
|
|
__arm_2d_impl_colour_filling(
|
|
(color_int *)rgb_buf,
|
|
buf_w,
|
|
©_size,
|
|
(color_int)draw_dsc->recolor.full);
|
|
}
|
|
|
|
bool is_accelerated = false;
|
|
|
|
if(!transform) {
|
|
if(LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) {
|
|
/* copy with colour keying */
|
|
|
|
/* *INDENT-OFF* */
|
|
__RECOLOUR_WRAPPER(
|
|
|
|
lv_color_t chrome_key = LV_COLOR_CHROMA_KEY;
|
|
/* calculate new chrome-key colour */
|
|
if(draw_dsc->recolor_opa > LV_OPA_MIN) {
|
|
__ARM_2D_PIXEL_BLENDING_OPA(
|
|
(color_int *) & (draw_dsc->recolor.full),
|
|
(color_int *) & (chrome_key.full),
|
|
draw_dsc->recolor_opa
|
|
);
|
|
}
|
|
|
|
__PREPARE_LL_ACCELERATION__();
|
|
|
|
if(blend_dsc.opa >= LV_OPA_MAX) {
|
|
__arm_2d_impl_cl_key_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size,
|
|
(color_int)chrome_key.full);
|
|
}
|
|
else {
|
|
__arm_2d_impl_alpha_blending_colour_keying(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size,
|
|
blend_dsc.opa,
|
|
(color_int)chrome_key.full);
|
|
}
|
|
is_accelerated = true;
|
|
)
|
|
/* *INDENT-ON* */
|
|
}
|
|
else if((LV_COLOR_DEPTH == 32)
|
|
&& !mask_any
|
|
&& (LV_IMG_CF_TRUE_COLOR_ALPHA == cf)) {
|
|
/* accelerate copy-with-source-masks-and-opacity */
|
|
|
|
/* *INDENT-OFF* */
|
|
__RECOLOUR_WRAPPER(
|
|
__PREPARE_LL_ACCELERATION__();
|
|
|
|
uint8_t * mask_temp_buf = NULL;
|
|
if(blend_dsc.opa < LV_OPA_MAX) {
|
|
mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth);
|
|
if(NULL == mask_temp_buf) {
|
|
LV_LOG_WARN(
|
|
"Failed to allocate memory for alpha mask,"
|
|
" use normal route instead.");
|
|
break;
|
|
}
|
|
lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth);
|
|
|
|
__arm_2d_impl_gray8_colour_filling_channel_mask_opacity(
|
|
mask_temp_buf,
|
|
src_stride,
|
|
(uint32_t *)
|
|
((uintptr_t)src_buf_tmp + LV_IMG_PX_SIZE_ALPHA_BYTE - 1),
|
|
src_stride,
|
|
©_size,
|
|
0xFF,
|
|
blend_dsc.opa);
|
|
|
|
__arm_2d_impl_src_msk_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
mask_temp_buf,
|
|
src_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
|
|
lv_mem_buf_release(mask_temp_buf);
|
|
}
|
|
else {
|
|
__arm_2d_impl_src_chn_msk_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
(uint32_t *)
|
|
((uintptr_t)src_buf_tmp + LV_IMG_PX_SIZE_ALPHA_BYTE - 1),
|
|
src_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
|
|
is_accelerated = true;
|
|
)
|
|
/* *INDENT-ON* */
|
|
}
|
|
else if(!mask_any
|
|
&& (LV_IMG_CF_RGB565A8 == cf)) {
|
|
/* accelerate copy-with-source-masks-and-opacity */
|
|
|
|
uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h;
|
|
/* *INDENT-OFF* */
|
|
__RECOLOUR_WRAPPER(
|
|
__PREPARE_LL_ACCELERATION__();
|
|
|
|
uint8_t * mask_temp_buf = NULL;
|
|
if(blend_dsc.opa < LV_OPA_MAX) {
|
|
mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth);
|
|
if(NULL == mask_temp_buf) {
|
|
LV_LOG_WARN(
|
|
"Failed to allocate memory for alpha mask,"
|
|
" use normal route instead.");
|
|
break;
|
|
}
|
|
lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth);
|
|
|
|
__arm_2d_impl_gray8_colour_filling_mask_opacity(
|
|
mask_temp_buf,
|
|
src_stride,
|
|
mask_after_rgb,
|
|
src_stride,
|
|
©_size,
|
|
0xFF,
|
|
blend_dsc.opa);
|
|
|
|
__arm_2d_impl_src_msk_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
mask_temp_buf,
|
|
src_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
|
|
lv_mem_buf_release(mask_temp_buf);
|
|
}
|
|
else {
|
|
__arm_2d_impl_src_msk_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
mask_after_rgb,
|
|
src_stride,
|
|
©_size,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
|
|
is_accelerated = true;
|
|
)
|
|
/* *INDENT-ON* */
|
|
}
|
|
else if(!mask_any && (cf == LV_IMG_CF_TRUE_COLOR)) {
|
|
/* accelerate copy-with-source-masks-and-opacity */
|
|
|
|
/* *INDENT-OFF* */
|
|
__RECOLOUR_WRAPPER(
|
|
__PREPARE_LL_ACCELERATION__();
|
|
|
|
if(blend_dsc.opa >= LV_OPA_MAX) {
|
|
__arm_2d_impl_copy(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size);
|
|
}
|
|
else {
|
|
__arm_2d_impl_alpha_blending(
|
|
(color_int *)src_buf_tmp,
|
|
src_stride,
|
|
(color_int *)dest_buf,
|
|
dest_stride,
|
|
©_size,
|
|
blend_dsc.opa);
|
|
}
|
|
is_accelerated = true;
|
|
)
|
|
/* *INDENT-ON* */
|
|
}
|
|
}
|
|
else if(!mask_any
|
|
#if defined(__ARM_2D_HAS_ANTI_ALIAS_TRANSFORM__) && __ARM_2D_HAS_ANTI_ALIAS_TRANSFORM__
|
|
&& (draw_dsc->antialias == 1)
|
|
#else
|
|
&& (draw_dsc->antialias == 0)
|
|
#endif
|
|
&& (draw_dsc->recolor_opa == LV_OPA_TRANSP)
|
|
&& (((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf)
|
|
|| (LV_IMG_CF_TRUE_COLOR == cf))
|
|
|| (LV_IMG_CF_RGB565A8 == cf)
|
|
#if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) && __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__
|
|
|| ((LV_IMG_CF_TRUE_COLOR_ALPHA == cf)
|
|
&& (LV_COLOR_DEPTH == 32))
|
|
#endif
|
|
)
|
|
) {
|
|
|
|
uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h;
|
|
/* *INDENT-OFF* */
|
|
__RECOLOUR_WRAPPER(
|
|
/* accelerate transform without re-color */
|
|
|
|
static arm_2d_tile_t target_tile_origin;
|
|
static arm_2d_tile_t target_tile;
|
|
arm_2d_region_t clip_region;
|
|
static arm_2d_region_t target_region;
|
|
|
|
lv_color_t * dest_buf = draw_ctx->buf;
|
|
|
|
target_tile_origin = (arm_2d_tile_t) {
|
|
.tRegion = {
|
|
.tSize = {
|
|
.iWidth = lv_area_get_width(draw_ctx->buf_area),
|
|
.iHeight = lv_area_get_height(draw_ctx->buf_area),
|
|
},
|
|
},
|
|
.tInfo.bIsRoot = true,
|
|
.phwBuffer = (uint16_t *)draw_ctx->buf,
|
|
};
|
|
|
|
clip_region = (arm_2d_region_t) {
|
|
.tLocation = {
|
|
.iX = draw_ctx->clip_area->x1 - draw_ctx->buf_area->x1,
|
|
.iY = draw_ctx->clip_area->y1 - draw_ctx->buf_area->y1,
|
|
},
|
|
.tSize = {
|
|
.iWidth = lv_area_get_width(draw_ctx->clip_area),
|
|
.iHeight = lv_area_get_height(draw_ctx->clip_area),
|
|
},
|
|
};
|
|
|
|
arm_2d_tile_generate_child(&target_tile_origin,
|
|
&clip_region,
|
|
&target_tile,
|
|
false);
|
|
|
|
static arm_2d_tile_t source_tile;
|
|
|
|
source_tile = (arm_2d_tile_t) {
|
|
.tRegion = {
|
|
.tSize = {
|
|
.iWidth = src_w,
|
|
.iHeight = src_h,
|
|
},
|
|
},
|
|
.tInfo.bIsRoot = true,
|
|
.pchBuffer = (uint8_t *)src_buf,
|
|
};
|
|
|
|
static arm_2d_location_t source_center, target_center;
|
|
source_center.iX = draw_dsc->pivot.x;
|
|
source_center.iY = draw_dsc->pivot.y;
|
|
|
|
if(LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) {
|
|
|
|
__ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
|
|
arm_2d_tile_transform_with_opacity_prepare,
|
|
&source_tile,
|
|
source_center,
|
|
ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
|
|
draw_dsc->zoom / 256.0f,
|
|
(color_int)LV_COLOR_CHROMA_KEY.full,
|
|
blend_dsc.opa);
|
|
|
|
arm_2d_tile_transform(
|
|
&target_tile,
|
|
&target_region,
|
|
NULL
|
|
);
|
|
is_accelerated = true;
|
|
}
|
|
#if ARM_2D_VERISON >= 10103
|
|
else if (LV_IMG_CF_TRUE_COLOR == cf) {
|
|
__ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
|
|
arm_2d_tile_transform_only_with_opacity_prepare,
|
|
&source_tile,
|
|
source_center,
|
|
ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
|
|
draw_dsc->zoom / 256.0f,
|
|
blend_dsc.opa);
|
|
|
|
arm_2d_tile_transform(
|
|
&target_tile,
|
|
&target_region,
|
|
NULL
|
|
);
|
|
is_accelerated = true;
|
|
}
|
|
#endif
|
|
else if (LV_IMG_CF_RGB565A8 == cf) {
|
|
static arm_2d_tile_t mask_tile;
|
|
mask_tile = source_tile;
|
|
|
|
mask_tile.tInfo.bHasEnforcedColour = true;
|
|
mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_COLOUR_GRAY8;
|
|
mask_tile.pchBuffer = mask_after_rgb;
|
|
|
|
__ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
|
|
arm_2d_tile_transform_with_src_mask_and_opacity_prepare,
|
|
&source_tile,
|
|
&mask_tile,
|
|
source_center,
|
|
ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
|
|
draw_dsc->zoom / 256.0f,
|
|
blend_dsc.opa
|
|
);
|
|
|
|
arm_2d_tile_transform(
|
|
&target_tile,
|
|
&target_region,
|
|
NULL
|
|
);
|
|
|
|
is_accelerated = true;
|
|
}
|
|
#if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) \
|
|
&& __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__
|
|
else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) &&
|
|
(LV_COLOR_DEPTH == 32)) {
|
|
static arm_2d_tile_t mask_tile;
|
|
mask_tile = source_tile;
|
|
|
|
mask_tile.tInfo.bHasEnforcedColour = true;
|
|
mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32;
|
|
mask_tile.pchBuffer += 3;
|
|
|
|
__ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
|
|
arm_2d_tile_transform_with_src_mask_and_opacity_prepare,
|
|
&source_tile,
|
|
&mask_tile,
|
|
source_center,
|
|
ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
|
|
draw_dsc->zoom / 256.0f,
|
|
blend_dsc.opa
|
|
);
|
|
|
|
arm_2d_tile_transform(
|
|
&target_tile,
|
|
&target_region,
|
|
NULL
|
|
);
|
|
|
|
is_accelerated = true;
|
|
}
|
|
#endif
|
|
)
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
/* *INDENT-OFF* */
|
|
if(!is_accelerated) while(blend_area.y1 <= y_last) {
|
|
/*Apply transformations if any or separate the channels*/
|
|
lv_area_t transform_area;
|
|
lv_area_copy(&transform_area, &blend_area);
|
|
lv_area_move(&transform_area, -coords->x1, -coords->y1);
|
|
if(transform) {
|
|
lv_draw_transform(draw_ctx, &transform_area, src_buf, src_w, src_h, src_w,
|
|
draw_dsc, cf, rgb_buf, mask_buf);
|
|
}
|
|
else {
|
|
convert_cb(&transform_area, src_buf, src_w, src_h, src_w, draw_dsc, cf, rgb_buf, mask_buf);
|
|
}
|
|
|
|
/*Apply recolor*/
|
|
if(draw_dsc->recolor_opa > LV_OPA_MIN) {
|
|
arm_2d_size_t copy_size = {
|
|
.iWidth = buf_w,
|
|
.iHeight = buf_h,
|
|
};
|
|
|
|
/* apply re-colour */
|
|
__arm_2d_impl_colour_filling_with_opacity(
|
|
(color_int *)rgb_buf,
|
|
buf_w,
|
|
©_size,
|
|
(color_int)draw_dsc->recolor.full,
|
|
draw_dsc->recolor_opa);
|
|
}
|
|
#if LV_USE_DRAW_MASKS
|
|
/*Apply the masks if any*/
|
|
if(mask_any) {
|
|
lv_coord_t y;
|
|
lv_opa_t * mask_buf_tmp = mask_buf;
|
|
for(y = blend_area.y1; y <= blend_area.y2; y++) {
|
|
lv_draw_mask_res_t mask_res_line;
|
|
mask_res_line = lv_draw_mask_apply(mask_buf_tmp, blend_area.x1, y, blend_w);
|
|
|
|
if(mask_res_line == LV_DRAW_MASK_RES_TRANSP) {
|
|
lv_memset_00(mask_buf_tmp, blend_w);
|
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
|
}
|
|
else if(mask_res_line == LV_DRAW_MASK_RES_CHANGED) {
|
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
|
}
|
|
mask_buf_tmp += blend_w;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*Blend*/
|
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
|
|
|
/*Go the the next lines*/
|
|
blend_area.y1 = blend_area.y2 + 1;
|
|
blend_area.y2 = blend_area.y1 + buf_h - 1;
|
|
if(blend_area.y2 > y_last) blend_area.y2 = y_last;
|
|
}
|
|
|
|
lv_mem_buf_release(mask_buf);
|
|
lv_mem_buf_release(rgb_buf);
|
|
}
|
|
}
|
|
|
|
static void lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)
|
|
{
|
|
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
|
|
|
arm_2d_op_wait_async(NULL);
|
|
if(disp->driver && disp->driver->wait_cb) {
|
|
disp->driver->wait_cb(disp->driver);
|
|
}
|
|
lv_draw_sw_wait_for_finish(draw_ctx);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
/**********************
|
|
* STATIC FUNCTIONS
|
|
**********************/
|
|
/* Separate the image channels to RGB and Alpha to match LV_COLOR_DEPTH settings*/
|
|
static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
|
|
lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
|
|
{
|
|
LV_UNUSED(draw_dsc);
|
|
LV_UNUSED(src_h);
|
|
LV_UNUSED(src_w);
|
|
|
|
const uint8_t * src_tmp8 = (const uint8_t *)src_buf;
|
|
lv_coord_t y;
|
|
lv_coord_t x;
|
|
|
|
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
|
uint32_t px_cnt = lv_area_get_size(dest_area);
|
|
lv_memset(abuf, 0xff, px_cnt);
|
|
|
|
src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
|
|
uint32_t dest_w = lv_area_get_width(dest_area);
|
|
uint32_t dest_w_byte = dest_w * sizeof(lv_color_t);
|
|
|
|
lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
|
|
lv_color_t * cbuf_tmp = cbuf;
|
|
for(y = dest_area->y1; y <= dest_area->y2; y++) {
|
|
lv_memcpy(cbuf_tmp, src_tmp8, dest_w_byte);
|
|
src_tmp8 += src_stride_byte;
|
|
cbuf_tmp += dest_w;
|
|
}
|
|
|
|
/*Make "holes" for with Chroma keying*/
|
|
if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
|
|
uint32_t i;
|
|
lv_color_t chk = LV_COLOR_CHROMA_KEY;
|
|
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
|
uint8_t * cbuf_uint = (uint8_t *)cbuf;
|
|
uint8_t chk_v = chk.full;
|
|
#elif LV_COLOR_DEPTH == 16
|
|
uint16_t * cbuf_uint = (uint16_t *)cbuf;
|
|
uint16_t chk_v = chk.full;
|
|
#elif LV_COLOR_DEPTH == 32
|
|
uint32_t * cbuf_uint = (uint32_t *)cbuf;
|
|
uint32_t chk_v = chk.full;
|
|
#endif
|
|
for(i = 0; i < px_cnt; i++) {
|
|
if(chk_v == cbuf_uint[i]) abuf[i] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
else if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
|
|
src_tmp8 += (src_stride * dest_area->y1 * LV_IMG_PX_SIZE_ALPHA_BYTE) + dest_area->x1 * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
|
|
|
lv_coord_t src_new_line_step_px = (src_stride - lv_area_get_width(dest_area));
|
|
lv_coord_t src_new_line_step_byte = src_new_line_step_px * LV_IMG_PX_SIZE_ALPHA_BYTE;
|
|
|
|
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
|
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
|
for(y = 0; y < dest_h; y++) {
|
|
for(x = 0; x < dest_w; x++) {
|
|
abuf[x] = src_tmp8[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
|
|
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
|
|
cbuf[x].full = *src_tmp8;
|
|
#elif LV_COLOR_DEPTH == 16
|
|
cbuf[x].full = *src_tmp8 + ((*(src_tmp8 + 1)) << 8);
|
|
#elif LV_COLOR_DEPTH == 32
|
|
cbuf[x] = *((lv_color_t *) src_tmp8);
|
|
cbuf[x].ch.alpha = 0xff;
|
|
#endif
|
|
src_tmp8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
|
|
|
|
}
|
|
cbuf += dest_w;
|
|
abuf += dest_w;
|
|
src_tmp8 += src_new_line_step_byte;
|
|
}
|
|
}
|
|
else if(cf == LV_IMG_CF_RGB565A8) {
|
|
src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
|
|
|
|
lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
|
|
|
|
lv_coord_t dest_h = lv_area_get_height(dest_area);
|
|
lv_coord_t dest_w = lv_area_get_width(dest_area);
|
|
for(y = 0; y < dest_h; y++) {
|
|
lv_memcpy(cbuf, src_tmp8, dest_w * sizeof(lv_color_t));
|
|
cbuf += dest_w;
|
|
src_tmp8 += src_stride_byte;
|
|
}
|
|
|
|
src_tmp8 = (const uint8_t *)src_buf;
|
|
src_tmp8 += sizeof(lv_color_t) * src_w * src_h;
|
|
src_tmp8 += src_stride * dest_area->y1 + dest_area->x1;
|
|
for(y = 0; y < dest_h; y++) {
|
|
lv_memcpy(abuf, src_tmp8, dest_w);
|
|
abuf += dest_w;
|
|
src_tmp8 += src_stride;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
static 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);
|
|
else {
|
|
#if __CORTEX_M >= 0x07
|
|
if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk)
|
|
SCB_CleanInvalidateDCache();
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif
|