/** * @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_colour_filling_with_opacity((uint8_t *)mask, mask_stride, ©_size, 0x00, 255 - 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