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