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 ©_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 ©_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 ©_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 ©_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 ©_size,
868 (color_int *)dest_buf,
869 dest_stride,
870 ©_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 ©_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 ©_size,
885 (color_int *)dest_buf,
886 dest_stride,
887 ©_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 ©_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 ©_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 ©_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 ©_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 ©_size,
1094 (color_int *)dest_buf,
1095 dest_stride,
1096 ©_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 ©_size,
1108 (color_int *)dest_buf,
1109 dest_stride,
1110 ©_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 ©_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 ©_size,
1152 (color_int *)dest_buf,
1153 dest_stride,
1154 ©_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 ©_size,
1165 (color_int *)dest_buf,
1166 dest_stride,
1167 ©_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 ©_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 ©_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 ©_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