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