1 /**
2 * @file lv_draw_sw_blend.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_sw.h"
10 #include "../../misc/lv_math.h"
11 #include "../../hal/lv_hal_disp.h"
12 #include "../../core/lv_refr.h"
13
14 /*********************
15 * DEFINES
16 *********************/
17
18 /**********************
19 * TYPEDEFS
20 **********************/
21
22 /**********************
23 * STATIC PROTOTYPES
24 **********************/
25
26 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
27 lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide);
28
29 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
30 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
31
32
33 #if LV_COLOR_SCREEN_TRANSP
34 LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
35 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
36 #endif /*LV_COLOR_SCREEN_TRANSP*/
37
38 #if LV_DRAW_COMPLEX
39 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color,
40 lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
41 #endif /*LV_DRAW_COMPLEX*/
42
43 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
44 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);
45
46 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
47 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);
48
49 #if LV_COLOR_SCREEN_TRANSP
50 LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
51 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
52 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
53
54 #endif /*LV_COLOR_SCREEN_TRANSP*/
55
56 #if LV_DRAW_COMPLEX
57 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
58 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
59 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
60
61 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
62 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
63 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
64 #endif /*LV_DRAW_COMPLEX*/
65
66 /**********************
67 * STATIC VARIABLES
68 **********************/
69
70 /**********************
71 * MACROS
72 **********************/
73 #define FILL_NORMAL_MASK_PX(color) \
74 if(*mask == LV_OPA_COVER) *dest_buf = color; \
75 else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \
76 mask++; \
77 dest_buf++;
78
79 #define MAP_NORMAL_MASK_PX(x) \
80 if(*mask_tmp_x) { \
81 if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \
82 else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \
83 } \
84 mask_tmp_x++;
85
86
87 /**********************
88 * GLOBAL FUNCTIONS
89 **********************/
90
lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)91 void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
92 {
93 /*Do not draw transparent things*/
94 if(dsc->opa <= LV_OPA_MIN) return;
95
96 lv_area_t blend_area;
97 if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
98
99 if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx);
100
101 ((lv_draw_sw_ctx_t *)draw_ctx)->blend(draw_ctx, dsc);
102 }
103
lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)104 LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
105 {
106 lv_opa_t * mask;
107 if(dsc->mask_buf == NULL) mask = NULL;
108 if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
109 else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
110 else mask = dsc->mask_buf;
111
112 lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
113
114 lv_area_t blend_area;
115 if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
116
117 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
118 lv_color_t * dest_buf = draw_ctx->buf;
119 if(disp->driver->set_px_cb == NULL) {
120 if(disp->driver->screen_transp == 0) {
121 dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
122 }
123 else {
124 /*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/
125 uint8_t * dest_buf8 = (uint8_t *) dest_buf;
126 dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
127 dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE;
128 dest_buf = (lv_color_t *)dest_buf8;
129 }
130 }
131
132 const lv_color_t * src_buf = dsc->src_buf;
133 lv_coord_t src_stride;
134 if(src_buf) {
135 src_stride = lv_area_get_width(dsc->blend_area);
136 src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
137 }
138 else {
139 src_stride = 0;
140 }
141
142 lv_coord_t mask_stride;
143 if(mask) {
144 /*Round the values in the mask if anti-aliasing is disabled*/
145 if(disp->driver->antialiasing == 0) {
146 int32_t mask_size = lv_area_get_size(dsc->mask_area);
147 int32_t i;
148 for(i = 0; i < mask_size; i++) {
149 mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP;
150 }
151 }
152
153 mask_stride = lv_area_get_width(dsc->mask_area);
154 mask += mask_stride * (blend_area.y1 - dsc->mask_area->y1) + (blend_area.x1 - dsc->mask_area->x1);
155
156 }
157 else {
158 mask_stride = 0;
159 }
160
161 lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
162
163
164 if(disp->driver->set_px_cb) {
165 if(dsc->src_buf == NULL) {
166 fill_set_px(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
167 }
168 else {
169 map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
170 }
171 }
172 #if LV_COLOR_SCREEN_TRANSP
173 else if(disp->driver->screen_transp) {
174 if(dsc->src_buf == NULL) {
175 fill_argb(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
176 }
177 else {
178 map_argb(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
179 }
180 }
181 #endif
182 else if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
183 if(dsc->src_buf == NULL) {
184 fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
185 }
186 else {
187 map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
188 }
189 }
190 else {
191 #if LV_DRAW_COMPLEX
192 if(dsc->src_buf == NULL) {
193 fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
194 }
195 else {
196 map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
197 }
198 #endif
199 }
200 }
201
202
203 /**********************
204 * STATIC FUNCTIONS
205 **********************/
206
fill_set_px(lv_color_t * dest_buf,const lv_area_t * blend_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stide)207 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
208 lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide)
209 {
210 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
211
212 int32_t x;
213 int32_t y;
214
215 if(mask == NULL) {
216 for(y = blend_area->y1; y <= blend_area->y2; y++) {
217 for(x = blend_area->x1; x <= blend_area->x2; x++) {
218 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, x, y, color, opa);
219 }
220 }
221 }
222 else {
223 int32_t w = lv_area_get_width(blend_area);
224 int32_t h = lv_area_get_height(blend_area);
225
226 for(y = 0; y < h; y++) {
227 for(x = 0; x < w; x++) {
228 if(mask[x]) {
229
230
231 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color,
232 (uint32_t)((uint32_t)opa * mask[x]) >> 8);
233 }
234 }
235 mask += mask_stide;
236 }
237 }
238 }
239
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)240 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
241 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
242 {
243 int32_t w = lv_area_get_width(dest_area);
244 int32_t h = lv_area_get_height(dest_area);
245
246 int32_t x;
247 int32_t y;
248
249 /*No mask*/
250 if(mask == NULL) {
251 if(opa >= LV_OPA_MAX) {
252 for(y = 0; y < h; y++) {
253 lv_color_fill(dest_buf, color, w);
254 dest_buf += dest_stride;
255 }
256 }
257 /*Has opacity*/
258 else {
259 lv_color_t last_dest_color = lv_color_black();
260 lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa);
261
262 #if LV_COLOR_MIX_ROUND_OFS == 0 && LV_COLOR_DEPTH == 16
263 /*lv_color_mix work with an optimized algorithm with 16 bit color depth.
264 *However, it introduces some rounded error on opa.
265 *Introduce the same error here too to make lv_color_premult produces the same result */
266 opa = (uint32_t)((uint32_t)opa + 4) >> 3;
267 opa = opa << 3;
268 #endif
269
270 uint16_t color_premult[3];
271 lv_color_premult(color, opa, color_premult);
272 lv_opa_t opa_inv = 255 - opa;
273
274 for(y = 0; y < h; y++) {
275 for(x = 0; x < w; x++) {
276 if(last_dest_color.full != dest_buf[x].full) {
277 last_dest_color = dest_buf[x];
278 last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
279 }
280 dest_buf[x] = last_res_color;
281 }
282 dest_buf += dest_stride;
283 }
284 }
285 }
286 /*Masked*/
287 else {
288 #if LV_COLOR_DEPTH == 16
289 uint32_t c32 = color.full + ((uint32_t)color.full << 16);
290 #endif
291 /*Only the mask matters*/
292 if(opa >= LV_OPA_MAX) {
293 int32_t x_end4 = w - 4;
294 for(y = 0; y < h; y++) {
295 for(x = 0; x < w && ((lv_uintptr_t)(mask) & 0x3); x++) {
296 FILL_NORMAL_MASK_PX(color)
297 }
298
299 for(; x <= x_end4; x += 4) {
300 uint32_t mask32 = *((uint32_t *)mask);
301 if(mask32 == 0xFFFFFFFF) {
302 #if LV_COLOR_DEPTH == 16
303 if((lv_uintptr_t)dest_buf & 0x3) {
304 *(dest_buf + 0) = color;
305 uint32_t * d = (uint32_t *)(dest_buf + 1);
306 *d = c32;
307 *(dest_buf + 3) = color;
308 }
309 else {
310 uint32_t * d = (uint32_t *)dest_buf;
311 *d = c32;
312 *(d + 1) = c32;
313 }
314 #else
315 dest_buf[0] = color;
316 dest_buf[1] = color;
317 dest_buf[2] = color;
318 dest_buf[3] = color;
319 #endif
320 dest_buf += 4;
321 mask += 4;
322 }
323 else if(mask32) {
324 FILL_NORMAL_MASK_PX(color)
325 FILL_NORMAL_MASK_PX(color)
326 FILL_NORMAL_MASK_PX(color)
327 FILL_NORMAL_MASK_PX(color)
328 }
329 else {
330 mask += 4;
331 dest_buf += 4;
332 }
333 }
334
335 for(; x < w ; x++) {
336 FILL_NORMAL_MASK_PX(color)
337 }
338 dest_buf += (dest_stride - w);
339 mask += (mask_stride - w);
340 }
341 }
342 /*With opacity*/
343 else {
344 /*Buffer the result color to avoid recalculating the same color*/
345 lv_color_t last_dest_color;
346 lv_color_t last_res_color;
347 lv_opa_t last_mask = LV_OPA_TRANSP;
348 last_dest_color.full = dest_buf[0].full;
349 last_res_color.full = dest_buf[0].full;
350 lv_opa_t opa_tmp = LV_OPA_TRANSP;
351
352 for(y = 0; y < h; y++) {
353 for(x = 0; x < w; x++) {
354 if(*mask) {
355 if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
356 (uint32_t)((uint32_t)(*mask) * opa) >> 8;
357 if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) {
358 if(opa_tmp == LV_OPA_COVER) last_res_color = color;
359 else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
360 last_mask = *mask;
361 last_dest_color.full = dest_buf[x].full;
362 }
363 dest_buf[x] = last_res_color;
364 }
365 mask++;
366 }
367 dest_buf += dest_stride;
368 mask += (mask_stride - w);
369 }
370 }
371 }
372 }
373
374 #if LV_COLOR_SCREEN_TRANSP
set_px_argb(uint8_t * buf,lv_color_t color,lv_opa_t opa)375 static inline void set_px_argb(uint8_t * buf, lv_color_t color, lv_opa_t opa)
376 {
377 lv_color_t bg_color;
378 lv_color_t res_color;
379 lv_opa_t bg_opa = buf[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
380 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
381 bg_color.full = buf[0];
382 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[1]);
383 if(buf[1] <= LV_OPA_MIN) return;
384 buf[0] = res_color.full;
385 #elif LV_COLOR_DEPTH == 16
386 bg_color.full = buf[0] + (buf[1] << 8);
387 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[2]);
388 if(buf[2] <= LV_OPA_MIN) return;
389 buf[0] = res_color.full & 0xff;
390 buf[1] = res_color.full >> 8;
391 #elif LV_COLOR_DEPTH == 32
392 bg_color = *((lv_color_t *)buf);
393 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf[3]);
394 if(buf[3] <= LV_OPA_MIN) return;
395 buf[0] = res_color.ch.blue;
396 buf[1] = res_color.ch.green;
397 buf[2] = res_color.ch.red;
398 #endif
399 }
400
set_px_argb_blend(uint8_t * buf,lv_color_t color,lv_opa_t opa,lv_color_t (* blend_fp)(lv_color_t,lv_color_t,lv_opa_t))401 static inline void set_px_argb_blend(uint8_t * buf, lv_color_t color, lv_opa_t opa, lv_color_t (*blend_fp)(lv_color_t,
402 lv_color_t, lv_opa_t))
403 {
404 static lv_color_t last_dest_color;
405 static lv_color_t last_src_color;
406 static lv_color_t last_res_color;
407 static uint32_t last_opa = 0xffff; /*Set to an invalid value for first*/
408
409 lv_color_t bg_color;
410
411 /*Get the BG color*/
412 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
413 if(buf[1] <= LV_OPA_MIN) return;
414 bg_color.full = buf[0];
415 #elif LV_COLOR_DEPTH == 16
416 if(buf[2] <= LV_OPA_MIN) return;
417 bg_color.full = buf[0] + (buf[1] << 8);
418 #elif LV_COLOR_DEPTH == 32
419 if(buf[3] <= LV_OPA_MIN) return;
420 bg_color = *((lv_color_t *)buf);
421 #endif
422
423 /*Get the result color*/
424 if(last_dest_color.full != bg_color.full || last_src_color.full != color.full || last_opa != opa) {
425 last_dest_color = bg_color;
426 last_src_color = color;
427 last_opa = opa;
428 last_res_color = blend_fp(last_src_color, last_dest_color, last_opa);
429 }
430
431 /*Set the result color*/
432 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
433 buf[0] = last_res_color.full;
434 #elif LV_COLOR_DEPTH == 16
435 buf[0] = last_res_color.full & 0xff;
436 buf[1] = last_res_color.full >> 8;
437 #elif LV_COLOR_DEPTH == 32
438 buf[0] = last_res_color.ch.blue;
439 buf[1] = last_res_color.ch.green;
440 buf[2] = last_res_color.ch.red;
441 #endif
442
443 }
444
fill_argb(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)445 LV_ATTRIBUTE_FAST_MEM static void fill_argb(lv_color_t * dest_buf, const lv_area_t * dest_area,
446 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
447 {
448 uint8_t * dest_buf8 = (uint8_t *) dest_buf;
449 int32_t w = lv_area_get_width(dest_area);
450 int32_t h = lv_area_get_height(dest_area);
451
452 int32_t x;
453 int32_t y;
454
455 uint8_t ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE];
456 lv_memcpy(ctmp, &color, sizeof(lv_color_t));
457 ctmp[LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = opa;
458
459 /*No mask*/
460 if(mask == NULL) {
461 if(opa >= LV_OPA_MAX) {
462 for(x = 0; x < w; x++) {
463 lv_memcpy(dest_buf8, ctmp, LV_IMG_PX_SIZE_ALPHA_BYTE);
464 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
465 }
466
467 dest_buf8 += (dest_stride - w) * LV_IMG_PX_SIZE_ALPHA_BYTE;
468
469 for(y = 1; y < h; y++) {
470 lv_memcpy(dest_buf8, (uint8_t *) dest_buf, w * LV_IMG_PX_SIZE_ALPHA_BYTE);
471 dest_buf8 += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
472 }
473 }
474 /*Has opacity*/
475 else {
476 uint8_t * dest_buf8_row = dest_buf8;
477 for(y = 0; y < h; y++) {
478 for(x = 0; x < w; x++) {
479 set_px_argb(dest_buf8, color, opa);
480 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
481 }
482 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
483 dest_buf8 = dest_buf8_row;
484 }
485 }
486 }
487 /*Masked*/
488 else {
489 /*Only the mask matters*/
490 if(opa >= LV_OPA_MAX) {
491 uint8_t * dest_buf8_row = dest_buf8;
492 for(y = 0; y < h; y++) {
493 for(x = 0; x < w; x++) {
494 set_px_argb(dest_buf8, color, *mask);
495 mask++;
496 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
497 }
498 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
499 dest_buf8 = dest_buf8_row;
500 }
501 }
502 /*With opacity*/
503 else {
504 /*Buffer the result color to avoid recalculating the same color*/
505 lv_opa_t last_mask = LV_OPA_TRANSP;
506 lv_opa_t opa_tmp = LV_OPA_TRANSP;
507
508 uint8_t * dest_buf8_row = dest_buf8;
509 for(y = 0; y < h; y++) {
510 for(x = 0; x < w; x++) {
511 if(*mask) {
512 if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
513 (uint32_t)((uint32_t)(*mask) * opa) >> 8;
514
515 set_px_argb(dest_buf8, color, opa_tmp);
516 }
517 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
518 mask++;
519 }
520 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
521 dest_buf8 = dest_buf8_row;
522 mask += (mask_stride - w);
523 }
524 }
525 }
526 }
527 #endif
528
529 #if LV_DRAW_COMPLEX
fill_blended(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,lv_blend_mode_t blend_mode)530 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area,
531 lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride,
532 lv_blend_mode_t blend_mode)
533 {
534
535 int32_t w = lv_area_get_width(dest_area);
536 int32_t h = lv_area_get_height(dest_area);
537
538 int32_t x;
539 int32_t y;
540
541 lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
542 switch(blend_mode) {
543 case LV_BLEND_MODE_ADDITIVE:
544 blend_fp = color_blend_true_color_additive;
545 break;
546 case LV_BLEND_MODE_SUBTRACTIVE:
547 blend_fp = color_blend_true_color_subtractive;
548 break;
549 case LV_BLEND_MODE_MULTIPLY:
550 blend_fp = color_blend_true_color_multiply;
551 break;
552 default:
553 LV_LOG_WARN("fill_blended: unsupported blend mode");
554 return;
555 }
556
557 /*Simple fill (maybe with opacity), no masking*/
558 if(mask == NULL) {
559 lv_color_t last_dest_color = dest_buf[0];
560 lv_color_t last_res_color = blend_fp(color, dest_buf[0], opa);
561 for(y = 0; y < h; y++) {
562 for(x = 0; x < w; x++) {
563 if(last_dest_color.full != dest_buf[x].full) {
564 last_dest_color = dest_buf[x];
565 last_res_color = blend_fp(color, dest_buf[x], opa);
566 }
567 dest_buf[x] = last_res_color;
568 }
569 dest_buf += dest_stride;
570 }
571 }
572 /*Masked*/
573 else {
574 /*Buffer the result color to avoid recalculating the same color*/
575 lv_color_t last_dest_color;
576 lv_color_t last_res_color;
577 lv_opa_t last_mask = LV_OPA_TRANSP;
578 last_dest_color = dest_buf[0];
579 lv_opa_t opa_tmp = mask[0] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[0] * opa) >> 8;
580 last_res_color = blend_fp(color, last_dest_color, opa_tmp);
581
582 for(y = 0; y < h; y++) {
583 for(x = 0; x < w; x++) {
584 if(mask[x] == 0) continue;
585 if(mask[x] != last_mask || last_dest_color.full != dest_buf[x].full) {
586 opa_tmp = mask[x] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[x] * opa) >> 8;
587
588 last_res_color = blend_fp(color, dest_buf[x], opa_tmp);
589 last_mask = mask[x];
590 last_dest_color.full = dest_buf[x].full;
591 }
592 dest_buf[x] = last_res_color;
593 }
594 dest_buf += dest_stride;
595 mask += mask_stride;
596 }
597 }
598 }
599 #endif
600
map_set_px(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)601 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
602 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)
603
604 {
605 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
606
607 int32_t w = lv_area_get_width(dest_area);
608 int32_t h = lv_area_get_height(dest_area);
609
610 int32_t x;
611 int32_t y;
612
613 if(mask == NULL) {
614 for(y = 0; y < h; y++) {
615 for(x = 0; x < w; x++) {
616 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
617 opa);
618 }
619 src_buf += src_stride;
620 }
621 }
622 else {
623 for(y = 0; y < h; y++) {
624 for(x = 0; x < w; x++) {
625 if(mask[x]) {
626 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
627 (uint32_t)((uint32_t)opa * mask[x]) >> 8);
628 }
629 }
630 mask += mask_stride;
631 src_buf += src_stride;
632 }
633 }
634 }
635
map_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)636 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
637 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)
638
639 {
640 int32_t w = lv_area_get_width(dest_area);
641 int32_t h = lv_area_get_height(dest_area);
642
643 int32_t x;
644 int32_t y;
645
646 /*Simple fill (maybe with opacity), no masking*/
647 if(mask == NULL) {
648 if(opa >= LV_OPA_MAX) {
649 for(y = 0; y < h; y++) {
650 lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
651 dest_buf += dest_stride;
652 src_buf += src_stride;
653 }
654 }
655 else {
656 for(y = 0; y < h; y++) {
657 for(x = 0; x < w; x++) {
658 dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
659 }
660 dest_buf += dest_stride;
661 src_buf += src_stride;
662 }
663 }
664 }
665 /*Masked*/
666 else {
667 /*Only the mask matters*/
668 if(opa > LV_OPA_MAX) {
669 int32_t x_end4 = w - 4;
670
671 for(y = 0; y < h; y++) {
672 const lv_opa_t * mask_tmp_x = mask;
673 #if 0
674 for(x = 0; x < w; x++) {
675 MAP_NORMAL_MASK_PX(x);
676 }
677 #else
678 for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
679 MAP_NORMAL_MASK_PX(x)
680 }
681
682 uint32_t * mask32 = (uint32_t *)mask_tmp_x;
683 for(; x < x_end4; x += 4) {
684 if(*mask32) {
685 if((*mask32) == 0xFFFFFFFF) {
686 dest_buf[x] = src_buf[x];
687 dest_buf[x + 1] = src_buf[x + 1];
688 dest_buf[x + 2] = src_buf[x + 2];
689 dest_buf[x + 3] = src_buf[x + 3];
690 }
691 else {
692 mask_tmp_x = (const lv_opa_t *)mask32;
693 MAP_NORMAL_MASK_PX(x)
694 MAP_NORMAL_MASK_PX(x + 1)
695 MAP_NORMAL_MASK_PX(x + 2)
696 MAP_NORMAL_MASK_PX(x + 3)
697 }
698 }
699 mask32++;
700 }
701
702 mask_tmp_x = (const lv_opa_t *)mask32;
703 for(; x < w ; x++) {
704 MAP_NORMAL_MASK_PX(x)
705 }
706 #endif
707 dest_buf += dest_stride;
708 src_buf += src_stride;
709 mask += mask_stride;
710 }
711 }
712 /*Handle opa and mask values too*/
713 else {
714 for(y = 0; y < h; y++) {
715 for(x = 0; x < w; x++) {
716 if(mask[x]) {
717 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
718 dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
719 }
720 }
721 dest_buf += dest_stride;
722 src_buf += src_stride;
723 mask += mask_stride;
724 }
725 }
726 }
727 }
728
729
730
731 #if LV_COLOR_SCREEN_TRANSP
map_argb(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,lv_blend_mode_t blend_mode)732 LV_ATTRIBUTE_FAST_MEM static void map_argb(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
733 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
734 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode)
735
736 {
737 uint8_t * dest_buf8 = (uint8_t *) dest_buf;
738
739 int32_t w = lv_area_get_width(dest_area);
740 int32_t h = lv_area_get_height(dest_area);
741
742 int32_t x;
743 int32_t y;
744
745 lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
746 switch(blend_mode) {
747 case LV_BLEND_MODE_ADDITIVE:
748 blend_fp = color_blend_true_color_additive;
749 break;
750 case LV_BLEND_MODE_SUBTRACTIVE:
751 blend_fp = color_blend_true_color_subtractive;
752 break;
753 case LV_BLEND_MODE_MULTIPLY:
754 blend_fp = color_blend_true_color_multiply;
755 break;
756 default:
757 blend_fp = NULL;
758 }
759
760 /*Simple fill (maybe with opacity), no masking*/
761 if(mask == NULL) {
762 if(opa >= LV_OPA_MAX) {
763 if(blend_fp == NULL && LV_COLOR_DEPTH == 32) {
764 for(y = 0; y < h; y++) {
765 lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
766 dest_buf += dest_stride;
767 src_buf += src_stride;
768 }
769 }
770 else {
771 uint8_t * dest_buf8_row = dest_buf8;
772 for(y = 0; y < h; y++) {
773 if(blend_fp == NULL) {
774 for(x = 0; x < w; x++) {
775 set_px_argb(dest_buf8, src_buf[x], LV_OPA_COVER);
776 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
777 }
778 }
779 else {
780 for(x = 0; x < w; x++) {
781 set_px_argb_blend(dest_buf8, src_buf[x], LV_OPA_COVER, blend_fp);
782 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
783 }
784 }
785
786 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
787 dest_buf8 = dest_buf8_row;
788 src_buf += src_stride;
789 }
790 }
791 }
792 /*No mask but opacity*/
793 else {
794 uint8_t * dest_buf8_row = dest_buf8;
795 for(y = 0; y < h; y++) {
796 if(blend_fp == NULL) {
797 for(x = 0; x < w; x++) {
798 set_px_argb(dest_buf8, src_buf[x], opa);
799 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
800 }
801 }
802 else {
803 for(x = 0; x < w; x++) {
804 set_px_argb_blend(dest_buf8, src_buf[x], opa, blend_fp);
805 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
806 }
807 }
808
809 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
810 dest_buf8 = dest_buf8_row;
811 src_buf += src_stride;
812 }
813 }
814 }
815 /*Masked*/
816 else {
817 /*Only the mask matters*/
818 if(opa > LV_OPA_MAX) {
819 uint8_t * dest_buf8_row = dest_buf8;
820 for(y = 0; y < h; y++) {
821 if(blend_fp == NULL) {
822 for(x = 0; x < w; x++) {
823 set_px_argb(dest_buf8, src_buf[x], mask[x]);
824 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
825 }
826 }
827 else {
828 for(x = 0; x < w; x++) {
829 set_px_argb_blend(dest_buf8, src_buf[x], mask[x], blend_fp);
830 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
831 }
832 }
833 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
834 dest_buf8 = dest_buf8_row;
835 src_buf += src_stride;
836 mask += mask_stride;
837 }
838 }
839 /*Handle opa and mask values too*/
840 else {
841 uint8_t * dest_buf8_row = dest_buf8;
842 for(y = 0; y < h; y++) {
843 if(blend_fp == NULL) {
844 for(x = 0; x < w; x++) {
845 if(mask[x]) {
846 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
847 set_px_argb(dest_buf8, src_buf[x], opa_tmp);
848 }
849 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
850 }
851 }
852 else {
853 for(x = 0; x < w; x++) {
854 if(mask[x]) {
855 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
856 set_px_argb_blend(dest_buf8, src_buf[x], opa_tmp, blend_fp);
857 }
858 dest_buf8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
859 }
860 }
861 dest_buf8_row += dest_stride * LV_IMG_PX_SIZE_ALPHA_BYTE;
862 dest_buf8 = dest_buf8_row;
863 src_buf += src_stride;
864 mask += mask_stride;
865 }
866 }
867 }
868 }
869 #endif
870
871
872 #if LV_DRAW_COMPLEX
map_blended(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,lv_blend_mode_t blend_mode)873 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
874 const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
875 const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode)
876 {
877
878 int32_t w = lv_area_get_width(dest_area);
879 int32_t h = lv_area_get_height(dest_area);
880
881 int32_t x;
882 int32_t y;
883
884 lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
885 switch(blend_mode) {
886 case LV_BLEND_MODE_ADDITIVE:
887 blend_fp = color_blend_true_color_additive;
888 break;
889 case LV_BLEND_MODE_SUBTRACTIVE:
890 blend_fp = color_blend_true_color_subtractive;
891 break;
892 case LV_BLEND_MODE_MULTIPLY:
893 blend_fp = color_blend_true_color_multiply;
894 break;
895 default:
896 LV_LOG_WARN("fill_blended: unsupported blend mode");
897 return;
898 }
899
900 lv_color_t last_dest_color;
901 lv_color_t last_src_color;
902 /*Simple fill (maybe with opacity), no masking*/
903 if(mask == NULL) {
904 last_dest_color = dest_buf[0];
905 last_src_color = src_buf[0];
906 lv_color_t last_res_color = blend_fp(last_src_color, last_dest_color, opa);
907 for(y = 0; y < h; y++) {
908 for(x = 0; x < w; x++) {
909 if(last_src_color.full != src_buf[x].full || last_dest_color.full != dest_buf[x].full) {
910 last_dest_color = dest_buf[x];
911 last_src_color = src_buf[x];
912 last_res_color = blend_fp(last_src_color, last_dest_color, opa);
913 }
914 dest_buf[x] = last_res_color;
915 }
916 dest_buf += dest_stride;
917 src_buf += src_stride;
918 }
919 }
920 /*Masked*/
921 else {
922 last_dest_color = dest_buf[0];
923 last_src_color = src_buf[0];
924 lv_opa_t last_opa = mask[0] >= LV_OPA_MAX ? opa : ((opa * mask[0]) >> 8);
925 lv_color_t last_res_color = blend_fp(last_src_color, last_dest_color, last_opa);
926 for(y = 0; y < h; y++) {
927 for(x = 0; x < w; x++) {
928 if(mask[x] == 0) continue;
929 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
930 if(last_src_color.full != src_buf[x].full || last_dest_color.full != dest_buf[x].full || last_opa != opa_tmp) {
931 last_dest_color = dest_buf[x];
932 last_src_color = src_buf[x];
933 last_opa = opa_tmp;
934 last_res_color = blend_fp(last_src_color, last_dest_color, last_opa);
935 }
936 dest_buf[x] = last_res_color;
937 }
938 dest_buf += dest_stride;
939 src_buf += src_stride;
940 mask += mask_stride;
941 }
942 }
943 }
944
color_blend_true_color_additive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)945 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
946 {
947
948 if(opa <= LV_OPA_MIN) return bg;
949
950 uint32_t tmp;
951 #if LV_COLOR_DEPTH == 1
952 tmp = bg.full + fg.full;
953 fg.full = LV_MIN(tmp, 1);
954 #else
955 tmp = bg.ch.red + fg.ch.red;
956 #if LV_COLOR_DEPTH == 8
957 fg.ch.red = LV_MIN(tmp, 7);
958 #elif LV_COLOR_DEPTH == 16
959 fg.ch.red = LV_MIN(tmp, 31);
960 #elif LV_COLOR_DEPTH == 32
961 fg.ch.red = LV_MIN(tmp, 255);
962 #endif
963
964 #if LV_COLOR_DEPTH == 8
965 tmp = bg.ch.green + fg.ch.green;
966 fg.ch.green = LV_MIN(tmp, 7);
967 #elif LV_COLOR_DEPTH == 16
968 #if LV_COLOR_16_SWAP == 0
969 tmp = bg.ch.green + fg.ch.green;
970 fg.ch.green = LV_MIN(tmp, 63);
971 #else
972 tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
973 tmp = LV_MIN(tmp, 63);
974 fg.ch.green_h = tmp >> 3;
975 fg.ch.green_l = tmp & 0x7;
976 #endif
977
978 #elif LV_COLOR_DEPTH == 32
979 tmp = bg.ch.green + fg.ch.green;
980 fg.ch.green = LV_MIN(tmp, 255);
981 #endif
982
983 tmp = bg.ch.blue + fg.ch.blue;
984 #if LV_COLOR_DEPTH == 8
985 fg.ch.blue = LV_MIN(tmp, 4);
986 #elif LV_COLOR_DEPTH == 16
987 fg.ch.blue = LV_MIN(tmp, 31);
988 #elif LV_COLOR_DEPTH == 32
989 fg.ch.blue = LV_MIN(tmp, 255);
990 #endif
991 #endif
992
993 if(opa == LV_OPA_COVER) return fg;
994
995 return lv_color_mix(fg, bg, opa);
996 }
997
color_blend_true_color_subtractive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)998 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
999 {
1000 if(opa <= LV_OPA_MIN) return bg;
1001
1002 int32_t tmp;
1003 tmp = bg.ch.red - fg.ch.red;
1004 fg.ch.red = LV_MAX(tmp, 0);
1005
1006 #if LV_COLOR_16_SWAP == 0
1007 tmp = bg.ch.green - fg.ch.green;
1008 fg.ch.green = LV_MAX(tmp, 0);
1009 #else
1010 tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
1011 tmp = LV_MAX(tmp, 0);
1012 fg.ch.green_h = tmp >> 3;
1013 fg.ch.green_l = tmp & 0x7;
1014 #endif
1015
1016 tmp = bg.ch.blue - fg.ch.blue;
1017 fg.ch.blue = LV_MAX(tmp, 0);
1018
1019 if(opa == LV_OPA_COVER) return fg;
1020
1021 return lv_color_mix(fg, bg, opa);
1022 }
1023
color_blend_true_color_multiply(lv_color_t fg,lv_color_t bg,lv_opa_t opa)1024 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
1025 {
1026 if(opa <= LV_OPA_MIN) return bg;
1027
1028 #if LV_COLOR_DEPTH == 32
1029 fg.ch.red = (fg.ch.red * bg.ch.red) >> 8;
1030 fg.ch.green = (fg.ch.green * bg.ch.green) >> 8;
1031 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 8;
1032 #elif LV_COLOR_DEPTH == 16
1033 fg.ch.red = (fg.ch.red * bg.ch.red) >> 5;
1034 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 5;
1035 LV_COLOR_SET_G(fg, (LV_COLOR_GET_G(fg) * LV_COLOR_GET_G(bg)) >> 6);
1036 #elif LV_COLOR_DEPTH == 8
1037 fg.ch.red = (fg.ch.red * bg.ch.red) >> 3;
1038 fg.ch.green = (fg.ch.green * bg.ch.green) >> 3;
1039 fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 2;
1040 #endif
1041
1042 if(opa == LV_OPA_COVER) return fg;
1043
1044 return lv_color_mix(fg, bg, opa);
1045 }
1046
1047 #endif
1048
1049