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