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