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