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