1 /**
2  * @file lv_draw_img.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sw.h"
10 #include "../lv_img_cache.h"
11 #include "../../hal/lv_hal_disp.h"
12 #include "../../misc/lv_log.h"
13 #include "../../core/lv_refr.h"
14 #include "../../misc/lv_mem.h"
15 #include "../../misc/lv_math.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 #define MAX_BUF_SIZE (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
30                        lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
31 
32 /**********************
33  *  STATIC VARIABLES
34  **********************/
35 
36 /**********************
37  *      MACROS
38  **********************/
39 
40 /**********************
41  *   GLOBAL FUNCTIONS
42  **********************/
43 
44 
lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx,const lv_draw_img_dsc_t * draw_dsc,const lv_area_t * coords,const uint8_t * src_buf,lv_img_cf_t cf)45 void LV_ATTRIBUTE_FAST_MEM lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx,
46                                                   const lv_draw_img_dsc_t * draw_dsc,
47                                                   const lv_area_t * coords, const uint8_t * src_buf,
48                                                   lv_img_cf_t cf)
49 {
50     /*Use the clip area as draw area*/
51     lv_area_t draw_area;
52     lv_area_copy(&draw_area, draw_ctx->clip_area);
53 
54     bool mask_any = lv_draw_mask_is_any(&draw_area);
55     bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
56 
57     lv_area_t blend_area;
58     lv_draw_sw_blend_dsc_t blend_dsc;
59 
60     lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
61     blend_dsc.opa = draw_dsc->opa;
62     blend_dsc.blend_mode = draw_dsc->blend_mode;
63     blend_dsc.blend_area = &blend_area;
64 
65     /*The simplest case just copy the pixels into the draw_buf*/
66     if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
67         blend_dsc.src_buf = (const lv_color_t *)src_buf;
68 
69         blend_dsc.blend_area = coords;
70         lv_draw_sw_blend(draw_ctx, &blend_dsc);
71     }
72     else if(!mask_any && !transform && cf == LV_IMG_CF_ALPHA_8BIT) {
73         lv_area_t clipped_coords;
74         if(!_lv_area_intersect(&clipped_coords, coords, draw_ctx->clip_area)) return;
75 
76         blend_dsc.mask_buf = (lv_opa_t *)src_buf;
77         blend_dsc.mask_area = coords;
78         blend_dsc.src_buf = NULL;
79         blend_dsc.color = draw_dsc->recolor;
80         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
81 
82         blend_dsc.blend_area = coords;
83         lv_draw_sw_blend(draw_ctx, &blend_dsc);
84     }
85 #if LV_COLOR_DEPTH == 16
86     else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
87         lv_coord_t src_w = lv_area_get_width(coords);
88         lv_coord_t src_h = lv_area_get_height(coords);
89         blend_dsc.src_buf = (const lv_color_t *)src_buf;
90         blend_dsc.mask_buf = (lv_opa_t *)src_buf;
91         blend_dsc.mask_buf += sizeof(lv_color_t) * src_w * src_h;
92         blend_dsc.blend_area = coords;
93         blend_dsc.mask_area = coords;
94         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
95         lv_draw_sw_blend(draw_ctx, &blend_dsc);
96     }
97 #endif
98     /*In the other cases every pixel need to be checked one-by-one*/
99     else {
100         blend_area.x1 = draw_ctx->clip_area->x1;
101         blend_area.x2 = draw_ctx->clip_area->x2;
102         blend_area.y1 = draw_ctx->clip_area->y1;
103         blend_area.y2 = draw_ctx->clip_area->y2;
104 
105         lv_coord_t src_w = lv_area_get_width(coords);
106         lv_coord_t src_h = lv_area_get_height(coords);
107         lv_coord_t blend_h = lv_area_get_height(&blend_area);
108         lv_coord_t blend_w = lv_area_get_width(&blend_area);
109 
110         uint32_t max_buf_size = MAX_BUF_SIZE;
111         uint32_t blend_size = lv_area_get_size(&blend_area);
112         uint32_t buf_h;
113         uint32_t buf_w = blend_w;
114         if(blend_size <= max_buf_size) {
115             buf_h = blend_h;
116         }
117         else {
118             /*Round to full lines*/
119             buf_h = max_buf_size / blend_w;
120         }
121 
122         /*Create buffers and masks*/
123         uint32_t buf_size = buf_w * buf_h;
124 
125         lv_color_t * rgb_buf = lv_mem_buf_get(buf_size * sizeof(lv_color_t));
126         lv_opa_t * mask_buf = lv_mem_buf_get(buf_size);
127         blend_dsc.mask_buf = mask_buf;
128         blend_dsc.mask_area = &blend_area;
129         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
130         blend_dsc.src_buf = rgb_buf;
131         lv_coord_t y_last = blend_area.y2;
132         blend_area.y2 = blend_area.y1 + buf_h - 1;
133 
134         lv_draw_mask_res_t mask_res_def = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
135                                            draw_dsc->zoom != LV_IMG_ZOOM_NONE) ?
136                                           LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
137         blend_dsc.mask_res = mask_res_def;
138 
139         while(blend_area.y1 <= y_last) {
140             /*Apply transformations if any or separate the channels*/
141             lv_area_t transform_area;
142             lv_area_copy(&transform_area, &blend_area);
143             lv_area_move(&transform_area, -coords->x1, -coords->y1);
144             if(transform) {
145                 lv_draw_transform(draw_ctx, &transform_area, src_buf, src_w, src_h, src_w,
146                                   draw_dsc, cf, rgb_buf, mask_buf);
147             }
148             else {
149                 convert_cb(&transform_area, src_buf, src_w, src_h, src_w, draw_dsc, cf, rgb_buf, mask_buf);
150             }
151 
152             /*Apply recolor*/
153             if(draw_dsc->recolor_opa > LV_OPA_MIN) {
154                 uint16_t premult_v[3];
155                 lv_opa_t recolor_opa = draw_dsc->recolor_opa;
156                 lv_color_t recolor = draw_dsc->recolor;
157                 lv_color_premult(recolor, recolor_opa, premult_v);
158                 recolor_opa = 255 - recolor_opa;
159                 uint32_t i;
160                 for(i = 0; i < buf_size; i++) {
161                     rgb_buf[i] = lv_color_mix_premult(premult_v, rgb_buf[i], recolor_opa);
162                 }
163             }
164 #if LV_DRAW_COMPLEX
165             /*Apply the masks if any*/
166             if(mask_any) {
167                 lv_coord_t y;
168                 lv_opa_t * mask_buf_tmp = mask_buf;
169                 for(y = blend_area.y1; y <= blend_area.y2; y++) {
170                     lv_draw_mask_res_t mask_res_line;
171                     mask_res_line = lv_draw_mask_apply(mask_buf_tmp, blend_area.x1, y, blend_w);
172 
173                     if(mask_res_line == LV_DRAW_MASK_RES_TRANSP) {
174                         lv_memset_00(mask_buf_tmp, blend_w);
175                         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
176                     }
177                     else if(mask_res_line == LV_DRAW_MASK_RES_CHANGED) {
178                         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
179                     }
180                     mask_buf_tmp += blend_w;
181                 }
182             }
183 #endif
184 
185             /*Blend*/
186             lv_draw_sw_blend(draw_ctx, &blend_dsc);
187 
188             /*Go the the next lines*/
189             blend_area.y1 = blend_area.y2 + 1;
190             blend_area.y2 = blend_area.y1 + buf_h - 1;
191             if(blend_area.y2 > y_last) blend_area.y2 = y_last;
192         }
193 
194         lv_mem_buf_release(mask_buf);
195         lv_mem_buf_release(rgb_buf);
196     }
197 }
198 
199 /**********************
200  *   STATIC FUNCTIONS
201  **********************/
202 
203 /* Separate the image channels to RGB and Alpha to match LV_COLOR_DEPTH settings*/
convert_cb(const lv_area_t * dest_area,const void * src_buf,lv_coord_t src_w,lv_coord_t src_h,lv_coord_t src_stride,const lv_draw_img_dsc_t * draw_dsc,lv_img_cf_t cf,lv_color_t * cbuf,lv_opa_t * abuf)204 static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coord_t src_w, lv_coord_t src_h,
205                        lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf)
206 {
207     LV_UNUSED(draw_dsc);
208     LV_UNUSED(src_h);
209     LV_UNUSED(src_w);
210 
211     const uint8_t * src_tmp8 = (const uint8_t *)src_buf;
212     lv_coord_t y;
213     lv_coord_t x;
214 
215     if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
216         uint32_t px_cnt = lv_area_get_size(dest_area);
217         lv_memset_ff(abuf, px_cnt);
218 
219         src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
220         uint32_t dest_w = lv_area_get_width(dest_area);
221         uint32_t dest_w_byte = dest_w * sizeof(lv_color_t);
222 
223         lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
224         lv_color_t * cbuf_tmp = cbuf;
225         for(y = dest_area->y1; y <= dest_area->y2; y++) {
226             lv_memcpy(cbuf_tmp, src_tmp8, dest_w_byte);
227             src_tmp8 += src_stride_byte;
228             cbuf_tmp += dest_w;
229         }
230 
231         /*Make "holes" for with Chroma keying*/
232         if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
233             uint32_t i;
234             lv_color_t chk = LV_COLOR_CHROMA_KEY;
235 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
236             uint8_t * cbuf_uint = (uint8_t *)cbuf;
237             uint8_t chk_v = chk.full;
238 #elif LV_COLOR_DEPTH == 16
239             uint16_t * cbuf_uint = (uint16_t *)cbuf;
240             uint16_t chk_v = chk.full;
241 #elif LV_COLOR_DEPTH == 32
242             uint32_t * cbuf_uint = (uint32_t *)cbuf;
243             uint32_t chk_v = chk.full;
244 #endif
245             for(i = 0; i < px_cnt; i++) {
246                 if(chk_v == cbuf_uint[i]) abuf[i] = 0x00;
247             }
248         }
249     }
250     else if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
251         src_tmp8 += (src_stride * dest_area->y1 * LV_IMG_PX_SIZE_ALPHA_BYTE) + dest_area->x1 * LV_IMG_PX_SIZE_ALPHA_BYTE;
252 
253         lv_coord_t src_new_line_step_px = (src_stride - lv_area_get_width(dest_area));
254         lv_coord_t src_new_line_step_byte = src_new_line_step_px * LV_IMG_PX_SIZE_ALPHA_BYTE;
255 
256         lv_coord_t dest_h = lv_area_get_height(dest_area);
257         lv_coord_t dest_w = lv_area_get_width(dest_area);
258         for(y = 0; y < dest_h; y++) {
259             for(x = 0; x < dest_w; x++) {
260                 abuf[x] = src_tmp8[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
261 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
262                 cbuf[x].full = *src_tmp8;
263 #elif LV_COLOR_DEPTH == 16
264                 cbuf[x].full = *src_tmp8 + ((*(src_tmp8 + 1)) << 8);
265 #elif LV_COLOR_DEPTH == 32
266                 cbuf[x] = *((lv_color_t *) src_tmp8);
267                 cbuf[x].ch.alpha = 0xff;
268 #endif
269                 src_tmp8 += LV_IMG_PX_SIZE_ALPHA_BYTE;
270 
271             }
272             cbuf += dest_w;
273             abuf += dest_w;
274             src_tmp8 += src_new_line_step_byte;
275         }
276     }
277     else if(cf == LV_IMG_CF_RGB565A8) {
278         src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t);
279 
280         lv_coord_t src_stride_byte = src_stride * sizeof(lv_color_t);
281 
282         lv_coord_t dest_h = lv_area_get_height(dest_area);
283         lv_coord_t dest_w = lv_area_get_width(dest_area);
284         for(y = 0; y < dest_h; y++) {
285             lv_memcpy(cbuf, src_tmp8, dest_w * sizeof(lv_color_t));
286             cbuf += dest_w;
287             src_tmp8 += src_stride_byte;
288         }
289 
290         src_tmp8 = (const uint8_t *)src_buf;
291         src_tmp8 += sizeof(lv_color_t) * src_w * src_h;
292         src_tmp8 += src_stride * dest_area->y1 + dest_area->x1;
293         for(y = 0; y < dest_h; y++) {
294             lv_memcpy(abuf, src_tmp8, dest_w);
295             abuf += dest_w;
296             src_tmp8 += src_stride;
297         }
298     }
299 }
300