1 /**
2  * @file lv_gpu_arm2d.c
3  *
4  */
5 
6 /*
7  * Copyright (C) 2010-2023 Arm Limited or its affiliates. All rights reserved.
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  *
11  * Licensed under the Apache License, Version 2.0 (the License); you may
12  * not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
19  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /*********************
25  *      INCLUDES
26  *********************/
27 #if defined(__clang__)
28     #pragma clang diagnostic ignored "-Wunknown-warning-option"
29     #pragma clang diagnostic ignored "-Wreserved-identifier"
30     #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
31     #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
32     #pragma clang diagnostic ignored "-Wcast-qual"
33     #pragma clang diagnostic ignored "-Wcast-align"
34     #pragma clang diagnostic ignored "-Wextra-semi-stmt"
35     #pragma clang diagnostic ignored "-Wsign-conversion"
36     #pragma clang diagnostic ignored "-Wunused-function"
37     #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
38     #pragma clang diagnostic ignored "-Wdouble-promotion"
39     #pragma clang diagnostic ignored "-Wunused-parameter"
40     #pragma clang diagnostic ignored "-Wimplicit-float-conversion"
41     #pragma clang diagnostic ignored "-Wimplicit-int-conversion"
42     #pragma clang diagnostic ignored "-Wtautological-pointer-compare"
43     #pragma clang diagnostic ignored "-Wsign-compare"
44     #pragma clang diagnostic ignored "-Wfloat-conversion"
45     #pragma clang diagnostic ignored "-Wmissing-prototypes"
46     #pragma clang diagnostic ignored "-Wpadded"
47     #pragma clang diagnostic ignored "-Wundef"
48     #pragma clang diagnostic ignored "-Wdeclaration-after-statement"
49     #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
50     #pragma clang diagnostic ignored "-Wunused-variable"
51     #pragma clang diagnostic ignored "-Wunused-but-set-variable"
52     #pragma clang diagnostic ignored "-Wint-conversion"
53 #endif
54 
55 
56 #include "lv_gpu_arm2d.h"
57 #include "../../core/lv_refr.h"
58 
59 #if LV_USE_GPU_ARM2D
60 #define __ARM_2D_IMPL__
61 #include "arm_2d.h"
62 #include "__arm_2d_impl.h"
63 
64 
65 #if defined(__IS_COMPILER_ARM_COMPILER_5__)
66     #pragma diag_suppress 174,177,188,68,513,144,1296
67 #elif defined(__IS_COMPILER_IAR__)
68     #pragma diag_suppress=Pa093
69 #elif defined(__IS_COMPILER_GCC__)
70     #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
71 #endif
72 
73 /*********************
74  *      DEFINES
75  *********************/
76 #if (   !defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__)                  \
77     ||  !__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__)                          \
78 &&  LV_COLOR_DEPTH == 32                                                        \
79 &&  !defined(__ARM_2D_LVGL_CFG_NO_WARNING__)
80 #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.
81 #endif
82 
83 #define MAX_BUF_SIZE (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
84 
85 #if LV_COLOR_DEPTH == 16
86 #define arm_2d_fill_colour              arm_2d_rgb16_fill_colour
87 #define arm_2d_fill_colour_with_alpha   arm_2d_rgb565_fill_colour_with_alpha
88 #define arm_2d_fill_colour_with_mask    arm_2d_rgb565_fill_colour_with_mask
89 #define arm_2d_fill_colour_with_mask_and_opacity                                \
90     arm_2d_rgb565_fill_colour_with_mask_and_opacity
91 #define arm_2d_tile_copy                arm_2d_rgb16_tile_copy
92 #define arm_2d_alpha_blending           arm_2d_rgb565_alpha_blending
93 #define arm_2d_tile_copy_with_src_mask  arm_2d_rgb565_tile_copy_with_src_mask
94 #define arm_2d_color_t                  arm_2d_color_rgb565_t
95 
96 /* arm-2d direct mode apis */
97 #define __arm_2d_impl_colour_filling    __arm_2d_impl_rgb16_colour_filling
98 #define __arm_2d_impl_colour_filling_with_opacity                               \
99     __arm_2d_impl_rgb565_colour_filling_with_opacity
100 #define __arm_2d_impl_colour_filling_mask                                       \
101     __arm_2d_impl_rgb565_colour_filling_mask
102 #define __arm_2d_impl_colour_filling_mask_opacity                               \
103     __arm_2d_impl_rgb565_colour_filling_mask_opacity
104 #define __arm_2d_impl_copy              __arm_2d_impl_rgb16_copy
105 #define __arm_2d_impl_alpha_blending    __arm_2d_impl_rgb565_alpha_blending
106 #define __arm_2d_impl_src_msk_copy      __arm_2d_impl_rgb565_src_msk_copy
107 #define __arm_2d_impl_src_chn_msk_copy  __arm_2d_impl_rgb565_src_chn_msk_copy
108 #define __arm_2d_impl_cl_key_copy       __arm_2d_impl_rgb16_cl_key_copy
109 #define __arm_2d_impl_alpha_blending_colour_keying                              \
110     __arm_2d_impl_rgb565_alpha_blending_colour_keying
111 #define arm_2d_tile_transform_with_src_mask_and_opacity_prepare                 \
112     arm_2dp_rgb565_tile_transform_with_src_mask_and_opacity_prepare
113 #define arm_2d_tile_transform_with_opacity_prepare                              \
114     arm_2dp_rgb565_tile_transform_with_opacity_prepare
115 #define arm_2d_tile_transform_only_with_opacity_prepare                         \
116     arm_2dp_rgb565_tile_transform_only_with_opacity_prepare
117 #define arm_2d_tile_transform_prepare                                           \
118     arm_2dp_rgb565_tile_transform_prepare
119 
120 #define __ARM_2D_PIXEL_BLENDING_OPA     __ARM_2D_PIXEL_BLENDING_OPA_RGB565
121 
122 #define color_int                       uint16_t
123 
124 #elif LV_COLOR_DEPTH == 32
125 #define arm_2d_fill_colour              arm_2d_rgb32_fill_colour
126 #define arm_2d_fill_colour_with_alpha   arm_2d_cccn888_fill_colour_with_alpha
127 #define arm_2d_fill_colour_with_mask    arm_2d_cccn888_fill_colour_with_mask
128 #define arm_2d_fill_colour_with_mask_and_opacity                                \
129     arm_2d_cccn888_fill_colour_with_mask_and_opacity
130 #define arm_2d_tile_copy                arm_2d_rgb32_tile_copy
131 #define arm_2d_alpha_blending           arm_2d_cccn888_alpha_blending
132 #define arm_2d_tile_copy_with_src_mask  arm_2d_cccn888_tile_copy_with_src_mask
133 #define arm_2d_color_t                  arm_2d_color_cccn888_t
134 
135 /* arm-2d direct mode apis */
136 #define __arm_2d_impl_colour_filling    __arm_2d_impl_rgb32_colour_filling
137 #define __arm_2d_impl_colour_filling_with_opacity                               \
138     __arm_2d_impl_cccn888_colour_filling_with_opacity
139 #define __arm_2d_impl_colour_filling_mask                                       \
140     __arm_2d_impl_cccn888_colour_filling_mask
141 #define __arm_2d_impl_colour_filling_mask_opacity                               \
142     __arm_2d_impl_cccn888_colour_filling_mask_opacity
143 #define __arm_2d_impl_copy              __arm_2d_impl_rgb32_copy
144 #define __arm_2d_impl_alpha_blending    __arm_2d_impl_cccn888_alpha_blending
145 #define __arm_2d_impl_src_msk_copy      __arm_2d_impl_cccn888_src_msk_copy
146 #define __arm_2d_impl_src_chn_msk_copy  __arm_2d_impl_cccn888_src_chn_msk_copy
147 #define __arm_2d_impl_cl_key_copy       __arm_2d_impl_rgb32_cl_key_copy
148 #define __arm_2d_impl_alpha_blending_colour_keying                              \
149     __arm_2d_impl_cccn888_alpha_blending_colour_keying
150 #define arm_2d_tile_transform_with_src_mask_and_opacity_prepare                 \
151     arm_2dp_cccn888_tile_transform_with_src_mask_and_opacity_prepare
152 #define arm_2d_tile_transform_with_opacity_prepare                              \
153     arm_2dp_cccn888_tile_transform_with_opacity_prepare
154 #define arm_2d_tile_transform_only_with_opacity_prepare                         \
155     arm_2dp_cccn888_tile_transform_only_with_opacity_prepare
156 #define arm_2d_tile_transform_prepare                                           \
157     arm_2dp_cccn888_tile_transform_prepare
158 
159 #define __ARM_2D_PIXEL_BLENDING_OPA     __ARM_2D_PIXEL_BLENDING_OPA_CCCN888
160 
161 #define color_int                       uint32_t
162 
163 #else
164 #error The specified LV_COLOR_DEPTH is not supported by this version of lv_gpu_arm2d.c.
165 #endif
166 
167 /* *INDENT-OFF* */
168 #define __PREPARE_LL_ACCELERATION__()                                           \
169             int32_t src_stride = lv_area_get_width(coords);                     \
170                                                                                 \
171             uint8_t px_size_byte = cf == LV_IMG_CF_TRUE_COLOR_ALPHA             \
172                                       ?  LV_IMG_PX_SIZE_ALPHA_BYTE              \
173                                       :  sizeof(lv_color_t);                    \
174                                                                                 \
175             const uint8_t * src_buf_tmp = src_buf;                              \
176             src_buf_tmp += src_stride                                           \
177                          * (draw_area.y1 - coords->y1)                          \
178                          * px_size_byte;                                        \
179             src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;          \
180                                                                                 \
181             lv_area_t blend_area2;                                              \
182             if(!_lv_area_intersect(&blend_area2,                                \
183                                    &draw_area,                                  \
184                                    draw_ctx->clip_area)) return;                \
185                                                                                 \
186             int32_t w = lv_area_get_width(&blend_area2);                        \
187             int32_t h = lv_area_get_height(&blend_area2);                       \
188                                                                                 \
189             lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);     \
190                                                                                 \
191             lv_color_t * dest_buf = draw_ctx->buf;                              \
192             dest_buf += dest_stride * (blend_area2.y1 - draw_ctx->buf_area->y1) \
193                         + (blend_area2.x1 - draw_ctx->buf_area->x1);            \
194                                                                                 \
195             arm_2d_size_t copy_size = {                                         \
196                 .iWidth = lv_area_get_width(&blend_area2),                      \
197                 .iHeight = lv_area_get_height(&blend_area2),                    \
198             }
199 
200 #define __PREPARE_TARGET_TILE__(__blend_area)                                   \
201         static arm_2d_tile_t target_tile;                                       \
202         static arm_2d_region_t target_region;                                   \
203                                                                                 \
204         lv_color_t * dest_buf = draw_ctx->buf;                                  \
205                                                                                 \
206         target_tile = (arm_2d_tile_t) {                                         \
207             .tRegion = {                                                        \
208                 .tSize = {                                                      \
209                     .iWidth = lv_area_get_width(draw_ctx->buf_area),            \
210                     .iHeight = lv_area_get_height(draw_ctx->buf_area),          \
211                 },                                                              \
212             },                                                                  \
213             .tInfo.bIsRoot = true,                                              \
214             .phwBuffer = (uint16_t *)draw_ctx->buf,                             \
215         };                                                                      \
216                                                                                 \
217         target_region = (arm_2d_region_t) {                                     \
218             .tLocation = {                                                      \
219                 .iX = (__blend_area).x1 - draw_ctx->buf_area->x1,               \
220                 .iY = (__blend_area).y1 - draw_ctx->buf_area->y1,               \
221             },                                                                  \
222             .tSize = {                                                          \
223                 .iWidth = lv_area_get_width(&(__blend_area)),                   \
224                 .iHeight = lv_area_get_height(&(__blend_area)),                 \
225             },                                                                  \
226         }
227 
228 #define __PREPARE_SOURCE_TILE__(__dsc, __blend_area)                            \
229         static arm_2d_tile_t source_tile_orig;                                  \
230         static arm_2d_tile_t source_tile;                                       \
231         const lv_color_t * src_buf = (__dsc)->src_buf;                          \
232         if (src_buf) {                                                          \
233             source_tile_orig = (arm_2d_tile_t) {                                \
234                 .tRegion = {                                                    \
235                     .tSize = {                                                  \
236                         .iWidth = lv_area_get_width((__dsc)->blend_area),       \
237                         .iHeight = lv_area_get_height((__dsc)->blend_area),     \
238                     },                                                          \
239                 },                                                              \
240                 .tInfo.bIsRoot = true,                                          \
241                 .phwBuffer = (uint16_t *)src_buf,                               \
242             };                                                                  \
243                                                                                 \
244             arm_2d_tile_generate_child(                                         \
245                 &source_tile_orig,                                              \
246                 (arm_2d_region_t []) {                                          \
247                     {                                                           \
248                         .tLocation = {                                          \
249                             .iX = (__blend_area).x1 - (__dsc)->blend_area->x1,  \
250                             .iY = (__blend_area).y1 - (__dsc)->blend_area->y1,  \
251                         },                                                      \
252                         .tSize = source_tile_orig.tRegion.tSize,                \
253                     }                                                           \
254                 },                                                              \
255                 &source_tile,                                                   \
256                 false);                                                         \
257             source_tile.tInfo.bDerivedResource = true;                          \
258         }
259 
260 #define __PREPARE_MASK_TILE__(__dsc, __blend_area, __mask, __is_chn)            \
261         static arm_2d_tile_t mask_tile_orig;                                    \
262         static arm_2d_tile_t mask_tile;                                         \
263         if(NULL != (__mask)) {                                                  \
264             mask_tile_orig = (arm_2d_tile_t) {                                  \
265                 .tRegion = {                                                    \
266                     .tSize = {                                                  \
267                         .iWidth = lv_area_get_width((__dsc)->mask_area),        \
268                         .iHeight = lv_area_get_height((__dsc)->mask_area),      \
269                     },                                                          \
270                 },                                                              \
271                 .tInfo = {                                                      \
272                     .bIsRoot = true,                                            \
273                     .bHasEnforcedColour = true,                                 \
274                     .tColourInfo = {                                            \
275                         .chScheme = (__is_chn) ? ARM_2D_CHANNEL_8in32           \
276                                                : ARM_2D_COLOUR_8BIT,            \
277                     },                                                          \
278                 },                                                              \
279                 .pchBuffer = ((uint8_t *)(__mask)) + (__is_chn) ? 3 : 0,        \
280             };                                                                  \
281                                                                                 \
282             arm_2d_tile_generate_child(                                         \
283                 &mask_tile_orig,                                                \
284                 (arm_2d_region_t []) {                                          \
285                     {                                                           \
286                         .tLocation = {                                          \
287                             .iX = (__dsc)->mask_area->x1 - (__blend_area).x1,   \
288                             .iY = (__dsc)->mask_area->y1 - (__blend_area).y1,   \
289                         },                                                      \
290                         .tSize = mask_tile_orig.tRegion.tSize,                  \
291                     }                                                           \
292                 },                                                              \
293                 &mask_tile,                                                     \
294                 false);                                                         \
295             mask_tile.tInfo.bDerivedResource = true;                            \
296         }
297 /* *INDENT-ON* */
298 
299 /* *INDENT-OFF* */
300 #define __RECOLOUR_WRAPPER(...)                                                 \
301     do {                                                                        \
302         lv_color_t *rgb_tmp_buf = NULL;                                         \
303         if(draw_dsc->recolor_opa > LV_OPA_MIN) {                                \
304             rgb_tmp_buf                                                         \
305                 = lv_mem_buf_get(src_w * src_h * sizeof(lv_color_t));           \
306             if (NULL == rgb_tmp_buf) {                                          \
307                 LV_LOG_WARN(                                                    \
308                     "Failed to allocate memory for accelerating recolour, "     \
309                     "use normal route instead.");                               \
310                 break;                                                          \
311             }                                                                   \
312             lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\
313             arm_2d_size_t copy_size = {                                         \
314                 .iWidth = src_w,                                                \
315                 .iHeight = src_h,                                               \
316             };                                                                  \
317             /* apply re-colour */                                               \
318             __arm_2d_impl_colour_filling_with_opacity(                          \
319                 (color_int *)rgb_tmp_buf,                                       \
320                 src_w,                                                          \
321                 &copy_size,                                                     \
322                 (color_int)draw_dsc->recolor.full,                              \
323                 draw_dsc->recolor_opa);                                         \
324                                                                                 \
325             /* replace src_buf for the following operation */                   \
326             src_buf = (const uint8_t *)rgb_tmp_buf;                             \
327         }                                                                       \
328         do {                                                                    \
329             __VA_ARGS__                                                         \
330         } while(0);                                                             \
331         if (NULL != rgb_tmp_buf) {                                              \
332             lv_mem_buf_release(rgb_tmp_buf);                                    \
333         }                                                                       \
334     } while(0);                                                                 \
335     src_buf = src_buf_org;
336 
337 #define __RECOLOUR_BEGIN()                                                      \
338     do {                                                                        \
339         lv_color_t *rgb_tmp_buf = NULL;                                         \
340         if(draw_dsc->recolor_opa > LV_OPA_MIN) {                                \
341             rgb_tmp_buf                                                         \
342                 = lv_mem_buf_get(src_w * src_h * sizeof(lv_color_t));           \
343             if (NULL == rgb_tmp_buf) {                                          \
344                 LV_LOG_WARN(                                                    \
345                     "Failed to allocate memory for accelerating recolour, "     \
346                     "use normal route instead.");                               \
347                 break;                                                          \
348             }                                                                   \
349             lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\
350             arm_2d_size_t copy_size = {                                         \
351                 .iWidth = src_w,                                                \
352                 .iHeight = src_h,                                               \
353             };                                                                  \
354             /* apply re-colour */                                               \
355             __arm_2d_impl_colour_filling_with_opacity(                          \
356                 (color_int *)rgb_tmp_buf,                                       \
357                 src_w,                                                          \
358                 &copy_size,                                                     \
359                 (color_int)draw_dsc->recolor.full,                              \
360                 draw_dsc->recolor_opa);                                         \
361                                                                                 \
362             /* replace src_buf for the following operation */                   \
363             src_buf = (const uint8_t *)rgb_tmp_buf;                             \
364         }                                                                       \
365         do {
366 
367 #define __RECOLOUR_END()                                                        \
368         } while(0);                                                             \
369         if (NULL != rgb_tmp_buf) {                                              \
370             lv_mem_buf_release(rgb_tmp_buf);                                    \
371         }                                                                       \
372     } while(0);                                                                 \
373     src_buf = src_buf_org;
374 
375 #define __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(__TRANS_PREPARE, ...)          \
376         do {                                                                    \
377             __TRANS_PREPARE(                                                    \
378                     NULL,                                                       \
379                     __VA_ARGS__);                                               \
380                                                                                 \
381             target_region = (arm_2d_region_t) {                                 \
382                 .tLocation = {                                                  \
383                     .iX = coords->x1 - draw_ctx->clip_area->x1,                 \
384                     .iY = coords->y1 - draw_ctx->clip_area->y1,                 \
385                 },                                                              \
386                 .tSize = {                                                      \
387                     .iWidth = lv_area_get_width(coords),                        \
388                     .iHeight = lv_area_get_height(coords),                      \
389                 },                                                              \
390             };                                                                  \
391                                                                                 \
392             arm_2d_size_t tTransSize                                            \
393                 = ARM_2D_CTRL.DefaultOP                                         \
394                     .tTransform.Source.ptTile->tRegion.tSize;                   \
395                                                                                 \
396             if (target_region.tSize.iWidth < tTransSize.iWidth) {               \
397                 int16_t iDelta = tTransSize.iWidth - target_region.tSize.iWidth;\
398                 target_region.tLocation.iX -= iDelta / 2;                       \
399                 target_region.tSize.iWidth = tTransSize.iWidth;                 \
400             }                                                                   \
401                                                                                 \
402             if (target_region.tSize.iHeight < tTransSize.iHeight) {             \
403                 int16_t iDelta                                                  \
404                     = tTransSize.iHeight - target_region.tSize.iHeight;         \
405                 target_region.tLocation.iY -= iDelta / 2;                       \
406                 target_region.tSize.iHeight = tTransSize.iHeight;               \
407             }                                                                   \
408         } while(0)
409 
410 /* *INDENT-ON* */
411 
412 /**********************
413  *      TYPEDEFS
414  **********************/
415 
416 /**********************
417  *  STATIC PROTOTYPES
418  **********************/
419 
420 #if __ARM_2D_HAS_HW_ACC__
421 static bool /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_fill_colour(const arm_2d_tile_t * target_tile,
422                                                                   const arm_2d_region_t * region,
423                                                                   lv_color_t color,
424                                                                   lv_opa_t opa,
425                                                                   const arm_2d_tile_t * mask_tile);
426 
427 static bool /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_tile_copy(const arm_2d_tile_t * target_tile,
428                                                                 const arm_2d_region_t * region,
429                                                                 arm_2d_tile_t * source_tile,
430                                                                 lv_opa_t opa,
431                                                                 arm_2d_tile_t * mask_tile);
432 #else
433 
434 static void convert_cb(const lv_area_t * dest_area,
435                        const void * src_buf,
436                        lv_coord_t src_w,
437                        lv_coord_t src_h,
438                        lv_coord_t src_stride,
439                        const lv_draw_img_dsc_t * draw_dsc,
440                        lv_img_cf_t cf,
441                        lv_color_t * cbuf,
442                        lv_opa_t * abuf);
443 
444 static bool /* LV_ATTRIBUTE_FAST_MEM */ arm_2d_fill_normal(lv_color_t * dest_buf,
445                                                            const lv_area_t * dest_area,
446                                                            lv_coord_t dest_stride,
447                                                            lv_color_t color,
448                                                            lv_opa_t opa,
449                                                            const lv_opa_t * mask,
450                                                            lv_coord_t mask_stride);
451 
452 static bool /* LV_ATTRIBUTE_FAST_MEM */ arm_2d_copy_normal(lv_color_t * dest_buf,
453                                                            const lv_area_t * dest_area,
454                                                            lv_coord_t dest_stride,
455                                                            const lv_color_t * src_buf,
456                                                            lv_coord_t src_stride,
457                                                            lv_opa_t opa,
458                                                            const lv_opa_t * mask,
459                                                            lv_coord_t mask_stride);
460 #endif
461 
462 static void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
463                                                             const lv_draw_sw_blend_dsc_t * dsc);
464 static void /* LV_ATTRIBUTE_FAST_MEM */ lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx);
465 static void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx,
466                                                                   const lv_draw_img_dsc_t * draw_dsc,
467                                                                   const lv_area_t * coords,
468                                                                   const uint8_t * src_buf,
469                                                                   lv_img_cf_t cf);
470 
471 /**********************
472  *  STATIC VARIABLES
473  **********************/
474 
475 /**********************
476  *      MACROS
477  **********************/
478 
479 /**********************
480  *   GLOBAL FUNCTIONS
481  **********************/
482 
lv_draw_arm2d_ctx_init(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)483 void lv_draw_arm2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
484 {
485     arm_2d_init();
486 
487     lv_draw_sw_init_ctx(drv, draw_ctx);
488 
489     lv_draw_arm2d_ctx_t * arm2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
490 
491     arm2d_draw_ctx->blend = lv_draw_arm2d_blend;
492     arm2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_arm2d_wait_cb;
493 
494 #if !__ARM_2D_HAS_HW_ACC__
495     arm2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_arm2d_img_decoded;
496 #endif
497 
498 }
499 
lv_draw_arm2d_ctx_deinit(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)500 void lv_draw_arm2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
501 {
502     LV_UNUSED(drv);
503     LV_UNUSED(draw_ctx);
504 }
505 
506 extern void test_flush(lv_color_t * color_p);
507 
508 #if __ARM_2D_HAS_HW_ACC__
lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)509 static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
510                                                       const lv_draw_sw_blend_dsc_t * dsc)
511 {
512     const lv_opa_t * mask;
513     if(dsc->mask_buf == NULL) mask = NULL;
514     if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
515     else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
516     else mask = dsc->mask_buf;
517 
518 
519     lv_area_t blend_area;
520     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) {
521         return;
522     }
523 
524     bool is_accelerated = false;
525 
526     if(dsc->blend_mode == LV_BLEND_MODE_NORMAL
527        &&    lv_area_get_size(&blend_area) > 100) {
528 
529         __PREPARE_TARGET_TILE__(blend_area);
530         __PREPARE_SOURCE_TILE__(dsc, blend_area);
531         __PREPARE_MASK_TILE__(dsc, blend_area, mask, false);
532 
533         if(src_buf) {
534             is_accelerated = lv_draw_arm2d_tile_copy(
535                                  &target_tile,
536                                  &target_region,
537                                  &source_tile,
538                                  dsc->opa,
539                                  (NULL == mask) ? NULL : &mask_tile);
540         }
541         else {
542             is_accelerated = lv_draw_arm2d_fill_colour(
543                                  &target_tile,
544                                  &target_region,
545                                  dsc->color,
546                                  dsc->opa,
547                                  (NULL == mask) ? NULL : &mask_tile);
548         }
549     }
550 
551     if(!is_accelerated) {
552         lv_draw_sw_blend_basic(draw_ctx, dsc);
553     }
554 }
555 
556 
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)557 static bool LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_fill_colour(const arm_2d_tile_t * target_tile,
558                                                             const arm_2d_region_t * region,
559                                                             lv_color_t color,
560                                                             lv_opa_t opa,
561                                                             const arm_2d_tile_t * mask_tile)
562 {
563     arm_fsm_rt_t result = (arm_fsm_rt_t)ARM_2D_ERR_NONE;
564 
565     if(NULL == mask_tile) {
566         if(opa >= LV_OPA_MAX) {
567             result = arm_2d_fill_colour(target_tile, region, color.full);
568         }
569         else {
570 #if LV_COLOR_SCREEN_TRANSP
571             return false;
572 #else
573             result = arm_2d_fill_colour_with_alpha(
574                          target_tile,
575                          region,
576             (arm_2d_color_t) {
577                 color.full
578             },
579             opa);
580 #endif
581         }
582     }
583     else {
584 
585         if(opa >= LV_OPA_MAX) {
586             result = arm_2d_fill_colour_with_mask(
587                          target_tile,
588                          region,
589                          mask_tile,
590             (arm_2d_color_t) {
591                 color.full
592             });
593         }
594         else {
595 #if LV_COLOR_SCREEN_TRANSP
596             return false;
597 #else
598             result = arm_2d_fill_colour_with_mask_and_opacity(
599                          target_tile,
600                          region,
601                          mask_tile,
602             (arm_2d_color_t) {
603                 color.full
604             },
605             opa);
606 #endif
607         }
608     }
609 
610     if(result < 0) {
611         /* error detected */
612         return false;
613     }
614 
615     return true;
616 
617 }
618 
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)619 static bool LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_tile_copy(const arm_2d_tile_t * target_tile,
620                                                           const arm_2d_region_t * region,
621                                                           arm_2d_tile_t * source_tile,
622                                                           lv_opa_t opa,
623                                                           arm_2d_tile_t * mask_tile)
624 {
625     arm_fsm_rt_t result = (arm_fsm_rt_t)ARM_2D_ERR_NONE;
626 
627     if(NULL == mask_tile) {
628         if(opa >= LV_OPA_MAX) {
629             result = arm_2d_tile_copy(source_tile,
630                                       target_tile,
631                                       region,
632                                       ARM_2D_CP_MODE_COPY);
633         }
634 #if LV_COLOR_SCREEN_TRANSP
635         else {
636             return false;  /* not supported */
637         }
638 #else
639         else {
640             result = arm_2d_alpha_blending(source_tile,
641                                            target_tile,
642                                            region,
643                                            opa);
644         }
645 #endif
646     }
647     else {
648 #if LV_COLOR_SCREEN_TRANSP
649         return false;       /* not support */
650 #else
651 
652         if(opa >= LV_OPA_MAX) {
653             result = arm_2d_tile_copy_with_src_mask(source_tile,
654                                                     mask_tile,
655                                                     target_tile,
656                                                     region,
657                                                     ARM_2D_CP_MODE_COPY);
658         }
659         else {
660             return false;
661         }
662 #endif
663     }
664 
665     if(result < 0) {
666         /* error detected */
667         return false;
668     }
669 
670     return true;
671 }
672 
lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)673 static void lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)
674 {
675     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
676 
677     arm_2d_op_wait_async(NULL);
678     if(disp->driver && disp->driver->wait_cb) {
679         disp->driver->wait_cb(disp->driver);
680     }
681     lv_draw_sw_wait_for_finish(draw_ctx);
682 }
683 #else
684 
685 
lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)686 static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx,
687                                                       const lv_draw_sw_blend_dsc_t * dsc)
688 {
689     const lv_opa_t * mask;
690     if(dsc->mask_buf == NULL) mask = NULL;
691     if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
692     else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
693     else mask = dsc->mask_buf;
694 
695     lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
696 
697     lv_area_t blend_area;
698     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
699 
700     //lv_disp_t * disp = _lv_refr_get_disp_refreshing();
701 
702     bool is_accelerated = false;
703     do {
704 
705         /* target buffer */
706         lv_color_t * dest_buf = draw_ctx->buf;
707         lv_disp_t * disp = _lv_refr_get_disp_refreshing();
708         if(disp->driver->screen_transp == 0) {
709             dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
710         }
711         else {
712             /*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/
713             uint8_t * dest_buf8 = (uint8_t *) dest_buf;
714             dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
715             dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
716             dest_buf = (lv_color_t *)dest_buf8;
717         }
718 
719         /* source buffer */
720         const lv_color_t * src_buf = dsc->src_buf;
721         lv_coord_t src_stride;
722         if(src_buf) {
723             src_stride = lv_area_get_width(dsc->blend_area);
724             src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
725         }
726         else {
727             src_stride = 0;
728         }
729 
730         lv_coord_t mask_stride;
731         if(mask) {
732             mask_stride = lv_area_get_width(dsc->mask_area);
733             mask += mask_stride * (blend_area.y1 - dsc->mask_area->y1) + (blend_area.x1 - dsc->mask_area->x1);
734         }
735         else {
736             mask_stride = 0;
737         }
738 
739         lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
740 
741         if(disp->driver->screen_transp) {
742             break;
743         }
744         if(dsc->src_buf == NULL) {
745             if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
746                 is_accelerated = arm_2d_fill_normal(dest_buf,
747                                                     &blend_area,
748                                                     dest_stride,
749                                                     dsc->color,
750                                                     dsc->opa,
751                                                     mask,
752                                                     mask_stride);
753             }
754         }
755         else {
756             if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
757                 is_accelerated = arm_2d_copy_normal(dest_buf,
758                                                     &blend_area,
759                                                     dest_stride,
760                                                     src_buf,
761                                                     src_stride,
762                                                     dsc->opa,
763                                                     mask,
764                                                     mask_stride);
765             }
766         }
767     } while(0);
768 
769     if(!is_accelerated) lv_draw_sw_blend_basic(draw_ctx, dsc);
770 }
771 
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)772 static bool LV_ATTRIBUTE_FAST_MEM arm_2d_fill_normal(lv_color_t * dest_buf,
773                                                      const lv_area_t * dest_area,
774                                                      lv_coord_t dest_stride,
775                                                      lv_color_t color,
776                                                      lv_opa_t opa,
777                                                      const lv_opa_t * mask,
778                                                      lv_coord_t mask_stride)
779 {
780     arm_2d_size_t target_size = {
781         .iWidth = lv_area_get_width(dest_area),
782         .iHeight = lv_area_get_height(dest_area),
783     };
784 
785     /*No mask*/
786     if(mask == NULL) {
787         if(opa >= LV_OPA_MAX) {
788             __arm_2d_impl_colour_filling((color_int *)dest_buf,
789                                          dest_stride,
790                                          &target_size,
791                                          color.full);
792         }
793         /*Has opacity*/
794         else {
795             __arm_2d_impl_colour_filling_with_opacity((color_int *)dest_buf,
796                                                       dest_stride,
797                                                       &target_size,
798                                                       color.full,
799                                                       opa);
800         }
801     }
802     /*Masked*/
803     else {
804         /*Only the mask matters*/
805         if(opa >= LV_OPA_MAX) {
806             __arm_2d_impl_colour_filling_mask((color_int *)dest_buf,
807                                               dest_stride,
808                                               (uint8_t *)mask,
809                                               mask_stride,
810                                               &target_size,
811                                               color.full);
812         }
813         /*With opacity*/
814         else {
815             __arm_2d_impl_colour_filling_mask_opacity((color_int *)dest_buf,
816                                                       dest_stride,
817                                                       (uint8_t *)mask,
818                                                       mask_stride,
819                                                       &target_size,
820                                                       color.full,
821                                                       opa);
822         }
823     }
824 
825     return true;
826 }
827 
828 
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)829 static bool LV_ATTRIBUTE_FAST_MEM arm_2d_copy_normal(lv_color_t * dest_buf,
830                                                      const lv_area_t * dest_area,
831                                                      lv_coord_t dest_stride,
832                                                      const lv_color_t * src_buf,
833                                                      lv_coord_t src_stride,
834                                                      lv_opa_t opa,
835                                                      const lv_opa_t * mask,
836                                                      lv_coord_t mask_stride)
837 
838 {
839     int32_t w = lv_area_get_width(dest_area);
840     int32_t h = lv_area_get_height(dest_area);
841 
842     arm_2d_size_t copy_size = {
843         .iWidth = lv_area_get_width(dest_area),
844         .iHeight = lv_area_get_height(dest_area),
845     };
846 
847     /*Simple fill (maybe with opacity), no masking*/
848     if(mask == NULL) {
849         if(opa >= LV_OPA_MAX) {
850             __arm_2d_impl_copy((color_int *)src_buf,
851                                src_stride,
852                                (color_int *)dest_buf,
853                                dest_stride,
854                                &copy_size);
855         }
856         else {
857             __arm_2d_impl_alpha_blending((color_int *)src_buf,
858                                          src_stride,
859                                          (color_int *)dest_buf,
860                                          dest_stride,
861                                          &copy_size,
862                                          opa);
863         }
864     }
865     /*Masked*/
866     else {
867         /*Only the mask matters*/
868         if(opa > LV_OPA_MAX) {
869             __arm_2d_impl_src_msk_copy((color_int *)src_buf,
870                                        src_stride,
871                                        (uint8_t *)mask,
872                                        mask_stride,
873                                        &copy_size,
874                                        (color_int *)dest_buf,
875                                        dest_stride,
876                                        &copy_size);
877         }
878         /*Handle opa and mask values too*/
879         else {
880             __arm_2d_impl_gray8_alpha_blending((uint8_t *)mask,
881                                                mask_stride,
882                                                (uint8_t *)mask,
883                                                mask_stride,
884                                                &copy_size,
885                                                opa);
886 
887             __arm_2d_impl_src_msk_copy((color_int *)src_buf,
888                                        src_stride,
889                                        (uint8_t *)mask,
890                                        mask_stride,
891                                        &copy_size,
892                                        (color_int *)dest_buf,
893                                        dest_stride,
894                                        &copy_size);
895         }
896     }
897 
898     return true;
899 }
900 
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)901 static void LV_ATTRIBUTE_FAST_MEM lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx,
902                                                             const lv_draw_img_dsc_t * draw_dsc,
903                                                             const lv_area_t * coords,
904                                                             const uint8_t * src_buf,
905                                                             lv_img_cf_t cf)
906 {
907     /*Use the clip area as draw area*/
908     lv_area_t draw_area;
909     lv_area_copy(&draw_area, draw_ctx->clip_area);
910     const uint8_t * src_buf_org = src_buf;
911 
912     bool mask_any = lv_draw_mask_is_any(&draw_area);
913     bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
914 
915     lv_area_t blend_area;
916     lv_draw_sw_blend_dsc_t blend_dsc;
917 
918     lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
919     blend_dsc.opa = draw_dsc->opa;
920     blend_dsc.blend_mode = draw_dsc->blend_mode;
921     blend_dsc.blend_area = &blend_area;
922 
923     if(lv_img_cf_is_chroma_keyed(cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
924     else if(cf == LV_IMG_CF_ALPHA_8BIT) {}
925     else if(cf == LV_IMG_CF_RGB565A8) {}
926     else if(lv_img_cf_has_alpha(cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
927     else cf = LV_IMG_CF_TRUE_COLOR;
928 
929 
930     /*The simplest case just copy the pixels into the draw_buf*/
931     if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
932         blend_dsc.src_buf = (const lv_color_t *)src_buf;
933 
934         blend_dsc.blend_area = coords;
935         lv_draw_sw_blend(draw_ctx, &blend_dsc);
936     }
937     else if(!mask_any && !transform && cf == LV_IMG_CF_ALPHA_8BIT) {
938         lv_area_t clipped_coords;
939         if(!_lv_area_intersect(&clipped_coords, coords, draw_ctx->clip_area)) return;
940 
941         blend_dsc.mask_buf = (lv_opa_t *)src_buf;
942         blend_dsc.mask_area = coords;
943         blend_dsc.src_buf = NULL;
944         blend_dsc.color = draw_dsc->recolor;
945         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
946 
947         blend_dsc.blend_area = coords;
948         lv_draw_sw_blend(draw_ctx, &blend_dsc);
949     }
950 #if LV_COLOR_DEPTH == 16
951     else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP &&
952             blend_dsc.opa >= LV_OPA_MAX) {
953         lv_coord_t src_w = lv_area_get_width(coords);
954         lv_coord_t src_h = lv_area_get_height(coords);
955         blend_dsc.src_buf = (const lv_color_t *)src_buf;
956         blend_dsc.mask_buf = (lv_opa_t *)src_buf;
957         blend_dsc.mask_buf += sizeof(lv_color_t) * src_w * src_h;
958         blend_dsc.blend_area = coords;
959         blend_dsc.mask_area = coords;
960         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
961         lv_draw_sw_blend(draw_ctx, &blend_dsc);
962     }
963 #endif
964     /*In the other cases every pixel need to be checked one-by-one*/
965     else {
966         blend_area.x1 = draw_ctx->clip_area->x1;
967         blend_area.x2 = draw_ctx->clip_area->x2;
968         blend_area.y1 = draw_ctx->clip_area->y1;
969         blend_area.y2 = draw_ctx->clip_area->y2;
970 
971         lv_coord_t src_w = lv_area_get_width(coords);
972         lv_coord_t src_h = lv_area_get_height(coords);
973         lv_coord_t blend_h = lv_area_get_height(&blend_area);
974         lv_coord_t blend_w = lv_area_get_width(&blend_area);
975 
976         uint32_t max_buf_size = MAX_BUF_SIZE;
977         uint32_t blend_size = lv_area_get_size(&blend_area);
978         uint32_t buf_h;
979         uint32_t buf_w = blend_w;
980         if(blend_size <= max_buf_size) {
981             buf_h = blend_h;
982         }
983         else {
984             /*Round to full lines*/
985             buf_h = max_buf_size / blend_w;
986         }
987 
988         /*Create buffers and masks*/
989         uint32_t buf_size = buf_w * buf_h;
990 
991         lv_color_t * rgb_buf = lv_mem_buf_get(buf_size * sizeof(lv_color_t));
992         lv_opa_t * mask_buf = lv_mem_buf_get(buf_size);
993         blend_dsc.mask_buf = mask_buf;
994         blend_dsc.mask_area = &blend_area;
995         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
996         blend_dsc.src_buf = rgb_buf;
997         lv_coord_t y_last = blend_area.y2;
998         blend_area.y2 = blend_area.y1 + buf_h - 1;
999 
1000         lv_draw_mask_res_t mask_res_def = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
1001                                            draw_dsc->zoom != LV_IMG_ZOOM_NONE) ?
1002                                           LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
1003         blend_dsc.mask_res = mask_res_def;
1004 
1005         if(cf == LV_IMG_CF_ALPHA_8BIT) {
1006             /* original code:
1007                lv_color_fill(rgb_buf, draw_dsc->recolor, buf_size);
1008              */
1009             arm_2d_size_t copy_size = {
1010                 .iWidth = buf_w,
1011                 .iHeight = buf_h,
1012             };
1013 
1014             /* apply re-colour */
1015             __arm_2d_impl_colour_filling(
1016                 (color_int *)rgb_buf,
1017                 buf_w,
1018                 &copy_size,
1019                 (color_int)draw_dsc->recolor.full);
1020         }
1021 
1022         bool is_accelerated = false;
1023 
1024         if(!transform) {
1025             if(LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf)  {
1026                 /* copy with colour keying */
1027 
1028                 /* *INDENT-OFF* */
1029                 __RECOLOUR_WRAPPER(
1030 
1031                     lv_color_t chrome_key = LV_COLOR_CHROMA_KEY;
1032                     /* calculate new chrome-key colour */
1033                     if(draw_dsc->recolor_opa > LV_OPA_MIN) {
1034                     __ARM_2D_PIXEL_BLENDING_OPA(
1035                         (color_int *) & (draw_dsc->recolor.full),
1036                         (color_int *) & (chrome_key.full),
1037                         draw_dsc->recolor_opa
1038                     );
1039                     }
1040 
1041                     __PREPARE_LL_ACCELERATION__();
1042 
1043                     if(blend_dsc.opa >= LV_OPA_MAX) {
1044                     __arm_2d_impl_cl_key_copy(
1045                         (color_int *)src_buf_tmp,
1046                         src_stride,
1047                         (color_int *)dest_buf,
1048                         dest_stride,
1049                         &copy_size,
1050                         (color_int)chrome_key.full);
1051                     }
1052                     else {
1053                         __arm_2d_impl_alpha_blending_colour_keying(
1054                             (color_int *)src_buf_tmp,
1055                             src_stride,
1056                             (color_int *)dest_buf,
1057                             dest_stride,
1058                             &copy_size,
1059                             blend_dsc.opa,
1060                             (color_int)chrome_key.full);
1061                     }
1062                     is_accelerated = true;
1063                 )
1064                 /* *INDENT-ON* */
1065             }
1066             else if((LV_COLOR_DEPTH == 32)
1067                     &&     !mask_any
1068                     && (LV_IMG_CF_TRUE_COLOR_ALPHA == cf)) {
1069                 /* accelerate copy-with-source-masks-and-opacity */
1070 
1071                 /* *INDENT-OFF* */
1072                 __RECOLOUR_WRAPPER(
1073                     __PREPARE_LL_ACCELERATION__();
1074 
1075                     uint8_t * mask_temp_buf = NULL;
1076                     if(blend_dsc.opa < LV_OPA_MAX) {
1077                         mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth);
1078                         if(NULL == mask_temp_buf) {
1079                             LV_LOG_WARN(
1080                                 "Failed to allocate memory for alpha mask,"
1081                                 " use normal route instead.");
1082                             break;
1083                         }
1084                         lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth);
1085 
1086                         __arm_2d_impl_gray8_colour_filling_channel_mask_opacity(
1087                             mask_temp_buf,
1088                             src_stride,
1089                             (uint32_t *)
1090                             ((uintptr_t)src_buf_tmp + LV_IMG_PX_SIZE_ALPHA_BYTE - 1),
1091                             src_stride,
1092                             &copy_size,
1093                             0xFF,
1094                             blend_dsc.opa);
1095 
1096                         __arm_2d_impl_src_msk_copy(
1097                             (color_int *)src_buf_tmp,
1098                             src_stride,
1099                             mask_temp_buf,
1100                             src_stride,
1101                             &copy_size,
1102                             (color_int *)dest_buf,
1103                             dest_stride,
1104                             &copy_size);
1105 
1106                         lv_mem_buf_release(mask_temp_buf);
1107                     }
1108                     else {
1109                         __arm_2d_impl_src_chn_msk_copy(
1110                             (color_int *)src_buf_tmp,
1111                             src_stride,
1112                             (uint32_t *)
1113                             ((uintptr_t)src_buf_tmp + LV_IMG_PX_SIZE_ALPHA_BYTE - 1),
1114                             src_stride,
1115                             &copy_size,
1116                             (color_int *)dest_buf,
1117                             dest_stride,
1118                             &copy_size);
1119                     }
1120 
1121                     is_accelerated = true;
1122                 )
1123                 /* *INDENT-ON* */
1124             }
1125             else if(!mask_any
1126                     && (LV_IMG_CF_RGB565A8 == cf)) {
1127                 /* accelerate copy-with-source-masks-and-opacity */
1128 
1129                 uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h;
1130                 /* *INDENT-OFF* */
1131                 __RECOLOUR_WRAPPER(
1132                     __PREPARE_LL_ACCELERATION__();
1133 
1134                     uint8_t * mask_temp_buf = NULL;
1135                     if(blend_dsc.opa < LV_OPA_MAX) {
1136                         mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth);
1137                         if(NULL == mask_temp_buf) {
1138                             LV_LOG_WARN(
1139                                 "Failed to allocate memory for alpha mask,"
1140                                 " use normal route instead.");
1141                             break;
1142                         }
1143                         lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth);
1144 
1145                         __arm_2d_impl_gray8_colour_filling_mask_opacity(
1146                             mask_temp_buf,
1147                             src_stride,
1148                             mask_after_rgb,
1149                             src_stride,
1150                             &copy_size,
1151                             0xFF,
1152                             blend_dsc.opa);
1153 
1154                         __arm_2d_impl_src_msk_copy(
1155                             (color_int *)src_buf_tmp,
1156                             src_stride,
1157                             mask_temp_buf,
1158                             src_stride,
1159                             &copy_size,
1160                             (color_int *)dest_buf,
1161                             dest_stride,
1162                             &copy_size);
1163 
1164                         lv_mem_buf_release(mask_temp_buf);
1165                     }
1166                     else {
1167                         __arm_2d_impl_src_msk_copy(
1168                             (color_int *)src_buf_tmp,
1169                             src_stride,
1170                             mask_after_rgb,
1171                             src_stride,
1172                             &copy_size,
1173                             (color_int *)dest_buf,
1174                             dest_stride,
1175                             &copy_size);
1176                     }
1177 
1178                     is_accelerated = true;
1179                 )
1180                 /* *INDENT-ON* */
1181             }
1182             else if(!mask_any && (cf == LV_IMG_CF_TRUE_COLOR)) {
1183                 /* accelerate copy-with-source-masks-and-opacity */
1184 
1185                 /* *INDENT-OFF* */
1186                 __RECOLOUR_WRAPPER(
1187                     __PREPARE_LL_ACCELERATION__();
1188 
1189                     if(blend_dsc.opa >= LV_OPA_MAX) {
1190                     __arm_2d_impl_copy(
1191                         (color_int *)src_buf_tmp,
1192                         src_stride,
1193                         (color_int *)dest_buf,
1194                         dest_stride,
1195                         &copy_size);
1196                     }
1197                     else {
1198                         __arm_2d_impl_alpha_blending(
1199                             (color_int *)src_buf_tmp,
1200                             src_stride,
1201                             (color_int *)dest_buf,
1202                             dest_stride,
1203                             &copy_size,
1204                             blend_dsc.opa);
1205                     }
1206                     is_accelerated = true;
1207                 )
1208                 /* *INDENT-ON* */
1209             }
1210         }
1211         else if(!mask_any
1212 #if defined(__ARM_2D_HAS_ANTI_ALIAS_TRANSFORM__) && __ARM_2D_HAS_ANTI_ALIAS_TRANSFORM__
1213                 && (draw_dsc->antialias == 1)
1214 #else
1215                 && (draw_dsc->antialias == 0)
1216 #endif
1217                 && (draw_dsc->recolor_opa == LV_OPA_TRANSP)
1218                 && (((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf)
1219                      || (LV_IMG_CF_TRUE_COLOR == cf))
1220                     || (LV_IMG_CF_RGB565A8 == cf)
1221 #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) &&  __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__
1222                     || ((LV_IMG_CF_TRUE_COLOR_ALPHA == cf)
1223                         && (LV_COLOR_DEPTH == 32))
1224 #endif
1225                    )
1226                ) {
1227 
1228             uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h;
1229             /* *INDENT-OFF* */
1230             __RECOLOUR_WRAPPER(
1231                 /* accelerate transform without re-color */
1232 
1233                 static arm_2d_tile_t target_tile_origin;
1234                 static arm_2d_tile_t target_tile;
1235                 arm_2d_region_t clip_region;
1236                 static arm_2d_region_t target_region;
1237 
1238                 lv_color_t * dest_buf = draw_ctx->buf;
1239 
1240                 target_tile_origin = (arm_2d_tile_t) {
1241                     .tRegion = {
1242                         .tSize = {
1243                             .iWidth = lv_area_get_width(draw_ctx->buf_area),
1244                             .iHeight = lv_area_get_height(draw_ctx->buf_area),
1245                         },
1246                     },
1247                     .tInfo.bIsRoot = true,
1248                     .phwBuffer = (uint16_t *)draw_ctx->buf,
1249                 };
1250 
1251                 clip_region = (arm_2d_region_t) {
1252                     .tLocation = {
1253                         .iX = draw_ctx->clip_area->x1 - draw_ctx->buf_area->x1,
1254                         .iY = draw_ctx->clip_area->y1 - draw_ctx->buf_area->y1,
1255                     },
1256                     .tSize = {
1257                         .iWidth = lv_area_get_width(draw_ctx->clip_area),
1258                         .iHeight = lv_area_get_height(draw_ctx->clip_area),
1259                     },
1260                 };
1261 
1262                 arm_2d_tile_generate_child(&target_tile_origin,
1263                                            &clip_region,
1264                                            &target_tile,
1265                                            false);
1266 
1267                 static arm_2d_tile_t source_tile;
1268 
1269                 source_tile = (arm_2d_tile_t) {
1270                     .tRegion = {
1271                         .tSize = {
1272                             .iWidth = src_w,
1273                             .iHeight = src_h,
1274                         },
1275                     },
1276                     .tInfo.bIsRoot = true,
1277                     .pchBuffer = (uint8_t *)src_buf,
1278                 };
1279 
1280                 static arm_2d_location_t source_center, target_center;
1281                 source_center.iX = draw_dsc->pivot.x;
1282                 source_center.iY = draw_dsc->pivot.y;
1283 
1284                 if(LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) {
1285 
1286                     __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
1287                         arm_2d_tile_transform_with_opacity_prepare,
1288                         &source_tile,
1289                         source_center,
1290                         ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
1291                         draw_dsc->zoom / 256.0f,
1292                         (color_int)LV_COLOR_CHROMA_KEY.full,
1293                         blend_dsc.opa);
1294 
1295                     arm_2d_tile_transform(
1296                         &target_tile,
1297                         &target_region,
1298                         NULL
1299                     );
1300                     is_accelerated = true;
1301                 }
1302     #if ARM_2D_VERISON >= 10103
1303                 else if (LV_IMG_CF_TRUE_COLOR == cf) {
1304                     __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
1305                         arm_2d_tile_transform_only_with_opacity_prepare,
1306                         &source_tile,
1307                         source_center,
1308                         ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
1309                         draw_dsc->zoom / 256.0f,
1310                         blend_dsc.opa);
1311 
1312                     arm_2d_tile_transform(
1313                         &target_tile,
1314                         &target_region,
1315                         NULL
1316                     );
1317                     is_accelerated = true;
1318                 }
1319     #endif
1320                 else if (LV_IMG_CF_RGB565A8 == cf) {
1321                     static arm_2d_tile_t mask_tile;
1322                     mask_tile = source_tile;
1323 
1324                     mask_tile.tInfo.bHasEnforcedColour = true;
1325                     mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_COLOUR_GRAY8;
1326                     mask_tile.pchBuffer = mask_after_rgb;
1327 
1328                     __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
1329                         arm_2d_tile_transform_with_src_mask_and_opacity_prepare,
1330                         &source_tile,
1331                         &mask_tile,
1332                         source_center,
1333                         ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
1334                         draw_dsc->zoom / 256.0f,
1335                         blend_dsc.opa
1336                         );
1337 
1338                     arm_2d_tile_transform(
1339                         &target_tile,
1340                         &target_region,
1341                         NULL
1342                     );
1343 
1344                     is_accelerated = true;
1345                 }
1346     #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__)          \
1347                 &&  __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__
1348                 else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) &&
1349                         (LV_COLOR_DEPTH == 32)) {
1350                     static arm_2d_tile_t mask_tile;
1351                     mask_tile = source_tile;
1352 
1353                     mask_tile.tInfo.bHasEnforcedColour = true;
1354                     mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32;
1355                     mask_tile.pchBuffer += 3;
1356 
1357                     __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(
1358                         arm_2d_tile_transform_with_src_mask_and_opacity_prepare,
1359                         &source_tile,
1360                         &mask_tile,
1361                         source_center,
1362                         ARM_2D_ANGLE((draw_dsc->angle / 10.0f)),
1363                         draw_dsc->zoom / 256.0f,
1364                         blend_dsc.opa
1365                         );
1366 
1367                     arm_2d_tile_transform(
1368                         &target_tile,
1369                         &target_region,
1370                         NULL
1371                     );
1372 
1373                     is_accelerated = true;
1374                 }
1375     #endif
1376             )
1377             /* *INDENT-ON* */
1378         }
1379 
1380         /* *INDENT-OFF* */
1381         if(!is_accelerated) while(blend_area.y1 <= y_last) {
1382             /*Apply transformations if any or separate the channels*/
1383             lv_area_t transform_area;
1384             lv_area_copy(&transform_area, &blend_area);
1385             lv_area_move(&transform_area, -coords->x1, -coords->y1);
1386             if(transform) {
1387                 lv_draw_transform(draw_ctx, &transform_area, src_buf, src_w, src_h, src_w,
1388                                   draw_dsc, cf, rgb_buf, mask_buf);
1389             }
1390             else {
1391                 convert_cb(&transform_area, src_buf, src_w, src_h, src_w, draw_dsc, cf, rgb_buf, mask_buf);
1392             }
1393 
1394             /*Apply recolor*/
1395             if(draw_dsc->recolor_opa > LV_OPA_MIN) {
1396                 arm_2d_size_t copy_size = {
1397                     .iWidth = buf_w,
1398                     .iHeight = buf_h,
1399                 };
1400 
1401                 /* apply re-colour */
1402                 __arm_2d_impl_colour_filling_with_opacity(
1403                     (color_int *)rgb_buf,
1404                     buf_w,
1405                     &copy_size,
1406                     (color_int)draw_dsc->recolor.full,
1407                     draw_dsc->recolor_opa);
1408             }
1409 #if LV_USE_DRAW_MASKS
1410             /*Apply the masks if any*/
1411             if(mask_any) {
1412                 lv_coord_t y;
1413                 lv_opa_t * mask_buf_tmp = mask_buf;
1414                 for(y = blend_area.y1; y <= blend_area.y2; y++) {
1415                     lv_draw_mask_res_t mask_res_line;
1416                     mask_res_line = lv_draw_mask_apply(mask_buf_tmp, blend_area.x1, y, blend_w);
1417 
1418                     if(mask_res_line == LV_DRAW_MASK_RES_TRANSP) {
1419                         lv_memset_00(mask_buf_tmp, blend_w);
1420                         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
1421                     }
1422                     else if(mask_res_line == LV_DRAW_MASK_RES_CHANGED) {
1423                         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
1424                     }
1425                     mask_buf_tmp += blend_w;
1426                 }
1427             }
1428 #endif
1429 
1430             /*Blend*/
1431             lv_draw_sw_blend(draw_ctx, &blend_dsc);
1432 
1433             /*Go the the next lines*/
1434             blend_area.y1 = blend_area.y2 + 1;
1435             blend_area.y2 = blend_area.y1 + buf_h - 1;
1436             if(blend_area.y2 > y_last) blend_area.y2 = y_last;
1437         }
1438 
1439         lv_mem_buf_release(mask_buf);
1440         lv_mem_buf_release(rgb_buf);
1441     }
1442 }
1443 
lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)1444 static void lv_gpu_arm2d_wait_cb(lv_draw_ctx_t * draw_ctx)
1445 {
1446     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
1447 
1448     arm_2d_op_wait_async(NULL);
1449     if(disp->driver && disp->driver->wait_cb) {
1450         disp->driver->wait_cb(disp->driver);
1451     }
1452     lv_draw_sw_wait_for_finish(draw_ctx);
1453 }
1454 
1455 
1456 #endif
1457 
1458 
1459 /**********************
1460  *   STATIC FUNCTIONS
1461  **********************/
1462 /* Separate the image channels to RGB and Alpha to match LV_COLOR_DEPTH settings*/
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)1463 static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
1464                        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)
1465 {
1466     LV_UNUSED(draw_dsc);
1467     LV_UNUSED(src_h);
1468     LV_UNUSED(src_w);
1469 
1470     const uint8_t * src_tmp8 = (const uint8_t *)src_buf;
1471     lv_coord_t y;
1472     lv_coord_t x;
1473 
1474     if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
1475         uint32_t px_cnt = lv_area_get_size(dest_area);
1476         lv_memset(abuf, 0xff, px_cnt);
1477 
1478         src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
1479         uint32_t dest_w = lv_area_get_width(dest_area);
1480         uint32_t dest_w_byte = dest_w * sizeof(lv_color_t);
1481 
1482         lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
1483         lv_color_t * cbuf_tmp = cbuf;
1484         for(y = dest_area->y1; y <= dest_area->y2; y++) {
1485             lv_memcpy(cbuf_tmp, src_tmp8, dest_w_byte);
1486             src_tmp8 += src_stride_byte;
1487             cbuf_tmp += dest_w;
1488         }
1489 
1490         /*Make "holes" for with Chroma keying*/
1491         if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
1492             uint32_t i;
1493             lv_color_t chk = LV_COLOR_CHROMA_KEY;
1494 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
1495             uint8_t * cbuf_uint = (uint8_t *)cbuf;
1496             uint8_t chk_v = chk.full;
1497 #elif LV_COLOR_DEPTH == 16
1498             uint16_t * cbuf_uint = (uint16_t *)cbuf;
1499             uint16_t chk_v = chk.full;
1500 #elif LV_COLOR_DEPTH == 32
1501             uint32_t * cbuf_uint = (uint32_t *)cbuf;
1502             uint32_t chk_v = chk.full;
1503 #endif
1504             for(i = 0; i < px_cnt; i++) {
1505                 if(chk_v == cbuf_uint[i]) abuf[i] = 0x00;
1506             }
1507         }
1508     }
1509     else if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
1510         src_tmp8 += (src_stride * dest_area->y1 * LV_IMG_PX_SIZE_ALPHA_BYTE) + dest_area->x1 * LV_IMG_PX_SIZE_ALPHA_BYTE;
1511 
1512         lv_coord_t src_new_line_step_px = (src_stride - lv_area_get_width(dest_area));
1513         lv_coord_t src_new_line_step_byte = src_new_line_step_px * LV_IMG_PX_SIZE_ALPHA_BYTE;
1514 
1515         lv_coord_t dest_h = lv_area_get_height(dest_area);
1516         lv_coord_t dest_w = lv_area_get_width(dest_area);
1517         for(y = 0; y < dest_h; y++) {
1518             for(x = 0; x < dest_w; x++) {
1519                 abuf[x] = src_tmp8[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
1520 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
1521                 cbuf[x].full = *src_tmp8;
1522 #elif LV_COLOR_DEPTH == 16
1523                 cbuf[x].full = *src_tmp8 + ((*(src_tmp8 + 1)) << 8);
1524 #elif LV_COLOR_DEPTH == 32
1525                 cbuf[x] = *((lv_color_t *) src_tmp8);
1526                 cbuf[x].ch.alpha = 0xff;
1527 #endif
1528                 src_tmp8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
1529 
1530             }
1531             cbuf += dest_w;
1532             abuf += dest_w;
1533             src_tmp8 += src_new_line_step_byte;
1534         }
1535     }
1536     else if(cf == LV_IMG_CF_RGB565A8) {
1537         src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
1538 
1539         lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
1540 
1541         lv_coord_t dest_h = lv_area_get_height(dest_area);
1542         lv_coord_t dest_w = lv_area_get_width(dest_area);
1543         for(y = 0; y < dest_h; y++) {
1544             lv_memcpy(cbuf, src_tmp8, dest_w * sizeof(lv_color_t));
1545             cbuf += dest_w;
1546             src_tmp8 += src_stride_byte;
1547         }
1548 
1549         src_tmp8 = (const uint8_t *)src_buf;
1550         src_tmp8 += sizeof(lv_color_t) * src_w * src_h;
1551         src_tmp8 += src_stride * dest_area->y1 + dest_area->x1;
1552         for(y = 0; y < dest_h; y++) {
1553             lv_memcpy(abuf, src_tmp8, dest_w);
1554             abuf += dest_w;
1555             src_tmp8 += src_stride;
1556         }
1557     }
1558 }
1559 
1560 #if 0
1561 static void invalidate_cache(void)
1562 {
1563     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
1564     if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver);
1565     else {
1566 #if __CORTEX_M >= 0x07
1567         if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk)
1568             SCB_CleanInvalidateDCache();
1569 #endif
1570     }
1571 }
1572 #endif
1573 
1574 #endif
1575