1 /**
2 * @file lv_draw_buf.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_buf_private.h"
10 #include "../misc/lv_types.h"
11 #include "../stdlib/lv_string.h"
12 #include "../core/lv_global.h"
13 #include "../misc/lv_math.h"
14 #include "../misc/lv_area_private.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19 #define default_handlers LV_GLOBAL_DEFAULT()->draw_buf_handlers
20 #define font_draw_buf_handlers LV_GLOBAL_DEFAULT()->font_draw_buf_handlers
21 #define image_cache_draw_buf_handlers LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers
22
23 /**********************
24 * TYPEDEFS
25 **********************/
26
27 /**********************
28 * STATIC PROTOTYPES
29 **********************/
30 static void * buf_malloc(size_t size, lv_color_format_t color_format);
31 static void buf_free(void * buf);
32 static void * buf_align(void * buf, lv_color_format_t color_format);
33 static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handler, size_t size_bytes,
34 lv_color_format_t color_format);
35 static void draw_buf_free(const lv_draw_buf_handlers_t * handler, void * buf);
36 static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format);
37 static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
38 static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area);
39
40 /**********************
41 * STATIC VARIABLES
42 **********************/
43
44 /**********************
45 * MACROS
46 **********************/
47
48 /**********************
49 * GLOBAL FUNCTIONS
50 **********************/
51
lv_draw_buf_init_handlers(void)52 void lv_draw_buf_init_handlers(void)
53 {
54 lv_draw_buf_init_with_default_handlers(&default_handlers);
55 lv_draw_buf_init_with_default_handlers(&font_draw_buf_handlers);
56 lv_draw_buf_init_with_default_handlers(&image_cache_draw_buf_handlers);
57 }
58
lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)59 void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)
60 {
61 lv_draw_buf_handlers_init(handlers, buf_malloc, buf_free, buf_align, NULL, NULL, width_to_stride);
62 }
63
lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,lv_draw_buf_malloc_cb buf_malloc_cb,lv_draw_buf_free_cb buf_free_cb,lv_draw_buf_align_cb align_pointer_cb,lv_draw_buf_cache_operation_cb invalidate_cache_cb,lv_draw_buf_cache_operation_cb flush_cache_cb,lv_draw_buf_width_to_stride_cb width_to_stride_cb)64 void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
65 lv_draw_buf_malloc_cb buf_malloc_cb,
66 lv_draw_buf_free_cb buf_free_cb,
67 lv_draw_buf_align_cb align_pointer_cb,
68 lv_draw_buf_cache_operation_cb invalidate_cache_cb,
69 lv_draw_buf_cache_operation_cb flush_cache_cb,
70 lv_draw_buf_width_to_stride_cb width_to_stride_cb)
71 {
72 lv_memzero(handlers, sizeof(lv_draw_buf_handlers_t));
73 handlers->buf_malloc_cb = buf_malloc_cb;
74 handlers->buf_free_cb = buf_free_cb;
75 handlers->align_pointer_cb = align_pointer_cb;
76 handlers->invalidate_cache_cb = invalidate_cache_cb;
77 handlers->flush_cache_cb = flush_cache_cb;
78 handlers->width_to_stride_cb = width_to_stride_cb;
79 }
80
lv_draw_buf_get_handlers(void)81 lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void)
82 {
83 return &default_handlers;
84 }
85
lv_draw_buf_get_font_handlers(void)86 lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void)
87 {
88 return &font_draw_buf_handlers;
89 }
90
lv_draw_buf_get_image_handlers(void)91 lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void)
92 {
93 return &image_cache_draw_buf_handlers;
94 }
95
lv_draw_buf_width_to_stride(uint32_t w,lv_color_format_t color_format)96 uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format)
97 {
98 return lv_draw_buf_width_to_stride_ex(&default_handlers, w, color_format);
99 }
100
lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers,uint32_t w,lv_color_format_t color_format)101 uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
102 lv_color_format_t color_format)
103 {
104 if(handlers->width_to_stride_cb) return handlers->width_to_stride_cb(w, color_format);
105 else return 0;
106 }
107
lv_draw_buf_align(void * data,lv_color_format_t color_format)108 void * lv_draw_buf_align(void * data, lv_color_format_t color_format)
109 {
110 return lv_draw_buf_align_ex(&default_handlers, data, color_format);
111 }
112
lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers,void * data,lv_color_format_t color_format)113 void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * data, lv_color_format_t color_format)
114 {
115 if(handlers->align_pointer_cb) return handlers->align_pointer_cb(data, color_format);
116 else return NULL;
117 }
118
lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf,const lv_area_t * area)119 void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
120 {
121 LV_ASSERT_NULL(draw_buf);
122 LV_ASSERT_NULL(draw_buf->handlers);
123
124 const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
125 if(!handlers->invalidate_cache_cb) {
126 return;
127 }
128
129 LV_PROFILER_DRAW_BEGIN;
130
131 lv_area_t full;
132 if(area == NULL) {
133 draw_buf_get_full_area(draw_buf, &full);
134 area = &full;
135 }
136
137 handlers->invalidate_cache_cb(draw_buf, area);
138 LV_PROFILER_DRAW_END;
139 }
140
lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf,const lv_area_t * area)141 void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
142 {
143 LV_ASSERT_NULL(draw_buf);
144 LV_ASSERT_NULL(draw_buf->handlers);
145
146 const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
147 if(!handlers->flush_cache_cb) {
148 return;
149 }
150
151 LV_PROFILER_DRAW_BEGIN;
152
153 lv_area_t full;
154 if(area == NULL) {
155 draw_buf_get_full_area(draw_buf, &full);
156 area = &full;
157 }
158
159 handlers->flush_cache_cb(draw_buf, area);
160 LV_PROFILER_DRAW_END;
161 }
162
lv_draw_buf_clear(lv_draw_buf_t * draw_buf,const lv_area_t * a)163 void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a)
164 {
165 LV_ASSERT_NULL(draw_buf);
166 LV_PROFILER_DRAW_BEGIN;
167
168 const lv_image_header_t * header = &draw_buf->header;
169 uint32_t stride = header->stride;
170
171 if(a == NULL) {
172 uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, 0, 0);
173 lv_memzero(buf, header->h * stride);
174 lv_draw_buf_flush_cache(draw_buf, a);
175 LV_PROFILER_DRAW_END;
176 return;
177 }
178
179 lv_area_t a_draw_buf;
180 a_draw_buf.x1 = 0;
181 a_draw_buf.y1 = 0;
182 a_draw_buf.x2 = draw_buf->header.w - 1;
183 a_draw_buf.y2 = draw_buf->header.h - 1;
184
185 lv_area_t a_clipped;
186 if(!lv_area_intersect(&a_clipped, a, &a_draw_buf)) {
187 LV_PROFILER_DRAW_END;
188 return;
189 }
190
191 if(lv_area_get_width(&a_clipped) <= 0) {
192 LV_PROFILER_DRAW_END;
193 return;
194 }
195
196 if(lv_area_get_height(&a_clipped) <= 0) {
197 LV_PROFILER_DRAW_END;
198 return;
199 }
200
201 uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, a_clipped.x1, a_clipped.y1);
202 uint8_t bpp = lv_color_format_get_bpp(header->cf);
203 uint32_t line_length = (lv_area_get_width(&a_clipped) * bpp + 7) >> 3;
204 int32_t y;
205 for(y = a_clipped.y1; y <= a_clipped.y2; y++) {
206 lv_memzero(buf, line_length);
207 buf += stride;
208 }
209 lv_draw_buf_flush_cache(draw_buf, a);
210 LV_PROFILER_DRAW_END;
211 }
212
lv_draw_buf_copy(lv_draw_buf_t * dest,const lv_area_t * dest_area,const lv_draw_buf_t * src,const lv_area_t * src_area)213 void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
214 const lv_draw_buf_t * src, const lv_area_t * src_area)
215 {
216 LV_PROFILER_DRAW_BEGIN;
217 uint8_t * dest_bufc;
218 uint8_t * src_bufc;
219 int32_t line_width;
220
221 /*Source and dest color format must be same. Color conversion is not supported yet.*/
222 LV_ASSERT_FORMAT_MSG(dest->header.cf == src->header.cf, "Color format mismatch: %d != %d",
223 dest->header.cf, src->header.cf);
224
225 if(dest_area == NULL) line_width = dest->header.w;
226 else line_width = lv_area_get_width(dest_area);
227
228 /* For indexed image, copy the palette if we are copying full image area*/
229 if(dest_area == NULL || src_area == NULL) {
230 if(LV_COLOR_FORMAT_IS_INDEXED(dest->header.cf)) {
231 lv_memcpy(dest->data, src->data, LV_COLOR_INDEXED_PALETTE_SIZE(dest->header.cf) * sizeof(lv_color32_t));
232 }
233 }
234
235 /*Check source and dest area have same width*/
236 if((src_area == NULL && line_width != src->header.w) || \
237 (src_area != NULL && line_width != lv_area_get_width(src_area))) {
238 LV_ASSERT_MSG(0, "Source and destination areas have different width");
239 LV_PROFILER_DRAW_END;
240 return;
241 }
242
243 if(src_area) src_bufc = lv_draw_buf_goto_xy(src, src_area->x1, src_area->y1);
244 else src_bufc = lv_draw_buf_goto_xy(src, 0, 0);
245
246 if(dest_area) dest_bufc = lv_draw_buf_goto_xy(dest, dest_area->x1, dest_area->y1);
247 else dest_bufc = lv_draw_buf_goto_xy(dest, 0, 0);
248
249 int32_t start_y, end_y;
250 if(dest_area) {
251 start_y = dest_area->y1;
252 end_y = dest_area->y2;
253 }
254 else {
255 start_y = 0;
256 end_y = dest->header.h - 1;
257 }
258
259 uint32_t dest_stride = dest->header.stride;
260 uint32_t src_stride = src->header.stride;
261 uint32_t line_bytes = (line_width * lv_color_format_get_bpp(dest->header.cf) + 7) >> 3;
262
263 for(; start_y <= end_y; start_y++) {
264 lv_memcpy(dest_bufc, src_bufc, line_bytes);
265 dest_bufc += dest_stride;
266 src_bufc += src_stride;
267 }
268 LV_PROFILER_DRAW_END;
269 }
270
lv_draw_buf_init(lv_draw_buf_t * draw_buf,uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride,void * data,uint32_t data_size)271 lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
272 void * data, uint32_t data_size)
273 {
274 LV_ASSERT_NULL(draw_buf);
275 if(draw_buf == NULL) return LV_RESULT_INVALID;
276
277 lv_memzero(draw_buf, sizeof(lv_draw_buf_t));
278 if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
279 if(stride * h > data_size) {
280 LV_LOG_WARN("Data size too small, required: %" LV_PRId32 ", provided: %" LV_PRId32, stride * h,
281 data_size);
282 return LV_RESULT_INVALID;
283 }
284
285 lv_image_header_t * header = &draw_buf->header;
286 header->w = w;
287 header->h = h;
288 header->cf = cf;
289 header->stride = stride;
290 header->flags = 0;
291 header->magic = LV_IMAGE_HEADER_MAGIC;
292
293 draw_buf->data = data;
294 draw_buf->unaligned_data = data;
295 draw_buf->handlers = &default_handlers;
296 draw_buf->data_size = data_size;
297 if(lv_draw_buf_align(data, cf) != draw_buf->unaligned_data) {
298 LV_LOG_WARN("Data is not aligned, ignored");
299 }
300 return LV_RESULT_OK;
301 }
302
lv_draw_buf_create(uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)303 lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
304 {
305 return lv_draw_buf_create_ex(&default_handlers, w, h, cf, stride);
306 }
307
lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers,uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)308 lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
309 lv_color_format_t cf, uint32_t stride)
310 {
311 LV_PROFILER_DRAW_BEGIN;
312 lv_draw_buf_t * draw_buf = lv_malloc_zeroed(sizeof(lv_draw_buf_t));
313 LV_ASSERT_MALLOC(draw_buf);
314 if(draw_buf == NULL) {
315 LV_PROFILER_DRAW_END;
316 return NULL;
317 }
318 if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
319
320 uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
321
322 void * buf = draw_buf_malloc(handlers, size, cf);
323 /*Do not assert here as LVGL or the app might just want to try creating a draw_buf*/
324 if(buf == NULL) {
325 LV_LOG_WARN("No memory: %"LV_PRIu32"x%"LV_PRIu32", cf: %d, stride: %"LV_PRIu32", %"LV_PRIu32"Byte, ",
326 w, h, cf, stride, size);
327 lv_free(draw_buf);
328 LV_PROFILER_DRAW_END;
329 return NULL;
330 }
331
332 draw_buf->header.w = w;
333 draw_buf->header.h = h;
334 draw_buf->header.cf = cf;
335 draw_buf->header.flags = LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
336 draw_buf->header.stride = stride;
337 draw_buf->header.magic = LV_IMAGE_HEADER_MAGIC;
338 draw_buf->data = lv_draw_buf_align(buf, cf);
339 draw_buf->unaligned_data = buf;
340 draw_buf->data_size = size;
341 draw_buf->handlers = handlers;
342 LV_PROFILER_DRAW_END;
343 return draw_buf;
344 }
345
lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)346 lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)
347 {
348 return lv_draw_buf_dup_ex(&default_handlers, draw_buf);
349 }
350
lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers,const lv_draw_buf_t * draw_buf)351 lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf)
352 {
353 LV_PROFILER_DRAW_BEGIN;
354 const lv_image_header_t * header = &draw_buf->header;
355 lv_draw_buf_t * new_buf = lv_draw_buf_create_ex(handlers, header->w, header->h, header->cf, header->stride);
356 if(new_buf == NULL) {
357 LV_PROFILER_DRAW_END;
358 return NULL;
359 }
360
361 new_buf->header.flags = draw_buf->header.flags;
362 new_buf->header.flags |= LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
363
364 /*Choose the smaller size to copy*/
365 uint32_t size = LV_MIN(draw_buf->data_size, new_buf->data_size);
366
367 /*Copy image data*/
368 lv_memcpy(new_buf->data, draw_buf->data, size);
369 LV_PROFILER_DRAW_END;
370 return new_buf;
371 }
372
lv_draw_buf_reshape(lv_draw_buf_t * draw_buf,lv_color_format_t cf,uint32_t w,uint32_t h,uint32_t stride)373 lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
374 uint32_t stride)
375 {
376 if(draw_buf == NULL) return NULL;
377 LV_PROFILER_DRAW_BEGIN;
378
379 /*If color format is unknown, keep using the original color format.*/
380 if(cf == LV_COLOR_FORMAT_UNKNOWN) cf = draw_buf->header.cf;
381 if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
382
383 uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
384
385 if(size > draw_buf->data_size) {
386 LV_LOG_TRACE("Draw buf too small for new shape");
387 LV_PROFILER_DRAW_END;
388 return NULL;
389 }
390
391 draw_buf->header.cf = cf;
392 draw_buf->header.w = w;
393 draw_buf->header.h = h;
394 draw_buf->header.stride = stride;
395
396 LV_PROFILER_DRAW_END;
397 return draw_buf;
398 }
399
lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)400 void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)
401 {
402 LV_ASSERT_NULL(draw_buf);
403 if(draw_buf == NULL) return;
404 LV_PROFILER_DRAW_BEGIN;
405
406 if(draw_buf->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
407 LV_ASSERT_NULL(draw_buf->handlers);
408
409 const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
410 draw_buf_free(handlers, draw_buf->unaligned_data);
411 lv_free(draw_buf);
412 }
413 else {
414 LV_LOG_ERROR("draw buffer is not allocated, ignored");
415 }
416 LV_PROFILER_DRAW_END;
417 }
418
lv_draw_buf_goto_xy(const lv_draw_buf_t * buf,uint32_t x,uint32_t y)419 void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
420 {
421 LV_ASSERT_NULL(buf);
422 if(buf == NULL) return NULL;
423
424 uint8_t * data = buf->data;
425
426 /*Skip palette*/
427 data += LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf) * sizeof(lv_color32_t);
428 data += buf->header.stride * y;
429
430 if(x == 0) return data;
431
432 return data + x * lv_color_format_get_bpp(buf->header.cf) / 8;
433 }
434
lv_draw_buf_adjust_stride(lv_draw_buf_t * src,uint32_t stride)435 lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)
436 {
437 LV_ASSERT_NULL(src);
438 LV_ASSERT_NULL(src->data);
439 if(src == NULL) return LV_RESULT_INVALID;
440 if(src->data == NULL) return LV_RESULT_INVALID;
441 LV_PROFILER_DRAW_BEGIN;
442
443 const lv_image_header_t * header = &src->header;
444 uint32_t w = header->w;
445 uint32_t h = header->h;
446
447 if(!lv_draw_buf_has_flag(src, LV_IMAGE_FLAGS_MODIFIABLE)) {
448 LV_PROFILER_DRAW_END;
449 return LV_RESULT_INVALID;
450 }
451
452 /*Use global stride*/
453 if(stride == 0) stride = lv_draw_buf_width_to_stride(w, header->cf);
454
455 /*Check if stride already match*/
456 if(header->stride == stride) {
457 LV_PROFILER_DRAW_END;
458 return LV_RESULT_OK;
459 }
460
461 /*Calculate the minimal stride allowed from bpp*/
462 uint32_t bpp = lv_color_format_get_bpp(header->cf);
463 uint32_t min_stride = (w * bpp + 7) >> 3;
464 if(stride < min_stride) {
465 LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
466 LV_PROFILER_DRAW_END;
467 return LV_RESULT_INVALID;
468 }
469
470 /*Check if buffer has enough space. */
471 uint32_t new_size = _calculate_draw_buf_size(w, h, header->cf, stride);
472 if(new_size > src->data_size) {
473 LV_PROFILER_DRAW_END;
474 return LV_RESULT_INVALID;
475 }
476
477 uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
478
479 if(stride > header->stride) {
480 /*Copy from the last line to the first*/
481 uint8_t * src_data = src->data + offset + header->stride * (h - 1);
482 uint8_t * dst_data = src->data + offset + stride * (h - 1);
483 for(uint32_t y = 0; y < h; y++) {
484 lv_memmove(dst_data, src_data, min_stride);
485 src_data -= header->stride;
486 dst_data -= stride;
487 }
488 }
489 else {
490 /*Copy from the first line to the last*/
491 uint8_t * src_data = src->data + offset;
492 uint8_t * dst_data = src->data + offset;
493 for(uint32_t y = 0; y < h; y++) {
494 lv_memmove(dst_data, src_data, min_stride);
495 src_data += header->stride;
496 dst_data += stride;
497 }
498 }
499
500 src->header.stride = stride;
501
502 LV_PROFILER_DRAW_END;
503 return LV_RESULT_OK;
504 }
505
lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)506 lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
507 {
508 LV_ASSERT_NULL(draw_buf);
509 if(draw_buf == NULL) return LV_RESULT_INVALID;
510
511 if(draw_buf->header.flags & LV_IMAGE_FLAGS_PREMULTIPLIED) return LV_RESULT_INVALID;
512 if((draw_buf->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) == 0) {
513 LV_LOG_WARN("draw buf is not modifiable: 0x%04x", draw_buf->header.flags);
514 return LV_RESULT_INVALID;
515 }
516 LV_PROFILER_DRAW_BEGIN;
517
518 /*Premultiply color with alpha, do case by case by judging color format*/
519 lv_color_format_t cf = draw_buf->header.cf;
520 if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
521 int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
522 lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
523 for(int i = 0; i < size; i++) {
524 lv_color_premultiply(&palette[i]);
525 }
526 }
527 else if(cf == LV_COLOR_FORMAT_ARGB8888) {
528 uint32_t h = draw_buf->header.h;
529 uint32_t w = draw_buf->header.w;
530 uint32_t stride = draw_buf->header.stride;
531 uint8_t * line = (uint8_t *)draw_buf->data;
532 for(uint32_t y = 0; y < h; y++) {
533 lv_color32_t * pixel = (lv_color32_t *)line;
534 for(uint32_t x = 0; x < w; x++) {
535 lv_color_premultiply(pixel);
536 pixel++;
537 }
538 line += stride;
539 }
540 }
541 else if(cf == LV_COLOR_FORMAT_RGB565A8) {
542 uint32_t h = draw_buf->header.h;
543 uint32_t w = draw_buf->header.w;
544 uint32_t stride = draw_buf->header.stride;
545 uint32_t alpha_stride = stride / 2;
546 uint8_t * line = (uint8_t *)draw_buf->data;
547 lv_opa_t * alpha = (lv_opa_t *)(line + stride * h);
548 for(uint32_t y = 0; y < h; y++) {
549 lv_color16_t * pixel = (lv_color16_t *)line;
550 for(uint32_t x = 0; x < w; x++) {
551 lv_color16_premultiply(pixel, alpha[x]);
552 pixel++;
553 }
554 line += stride;
555 alpha += alpha_stride;
556 }
557 }
558 else if(cf == LV_COLOR_FORMAT_ARGB8565) {
559 uint32_t h = draw_buf->header.h;
560 uint32_t w = draw_buf->header.w;
561 uint32_t stride = draw_buf->header.stride;
562 uint8_t * line = (uint8_t *)draw_buf->data;
563 for(uint32_t y = 0; y < h; y++) {
564 uint8_t * pixel = line;
565 for(uint32_t x = 0; x < w; x++) {
566 uint8_t alpha = pixel[2];
567 lv_color16_premultiply((lv_color16_t *)pixel, alpha);
568 pixel += 3;
569 }
570 line += stride;
571 }
572 }
573 else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
574 /*Pass*/
575 }
576 else {
577 LV_LOG_WARN("draw buf has no alpha, cf: %d", cf);
578 }
579
580 draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
581
582 LV_PROFILER_DRAW_END;
583 return LV_RESULT_OK;
584 }
585
lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf,uint8_t index,lv_color32_t color)586 void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color)
587 {
588 LV_ASSERT_NULL(draw_buf);
589 if(draw_buf == NULL) return;
590
591 if(!LV_COLOR_FORMAT_IS_INDEXED(draw_buf->header.cf)) {
592 LV_LOG_WARN("Not indexed color format");
593 return;
594 }
595
596 lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
597 palette[index] = color;
598 }
599
lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf,lv_image_flags_t flag)600 bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
601 {
602 return draw_buf->header.flags & flag;
603 }
604
lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf,lv_image_flags_t flag)605 void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
606 {
607 draw_buf->header.flags |= flag;
608 }
609
lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf,lv_image_flags_t flag)610 void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
611 {
612 draw_buf->header.flags &= ~flag;
613 }
614
lv_draw_buf_from_image(lv_draw_buf_t * buf,const lv_image_dsc_t * img)615 void lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img)
616 {
617 lv_draw_buf_init(buf, img->header.w, img->header.h, img->header.cf, img->header.stride,
618 (void *)img->data, img->data_size);
619 buf->header.flags = img->header.flags;
620 }
621
lv_draw_buf_to_image(const lv_draw_buf_t * buf,lv_image_dsc_t * img)622 void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img)
623 {
624 lv_memcpy((void *)img, buf, sizeof(lv_image_dsc_t));
625 }
626
lv_image_buf_set_palette(lv_image_dsc_t * dsc,uint8_t id,lv_color32_t c)627 void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c)
628 {
629 LV_LOG_WARN("Deprecated API, use lv_draw_buf_set_palette instead.");
630 lv_draw_buf_set_palette((lv_draw_buf_t *)dsc, id, c);
631 }
632
lv_image_buf_free(lv_image_dsc_t * dsc)633 void lv_image_buf_free(lv_image_dsc_t * dsc)
634 {
635 LV_LOG_WARN("Deprecated API, use lv_draw_buf_destroy instead.");
636 if(dsc != NULL) {
637 if(dsc->data != NULL)
638 lv_free((void *)dsc->data);
639
640 lv_free((void *)dsc);
641 }
642 }
643
644 /**********************
645 * STATIC FUNCTIONS
646 **********************/
647
buf_malloc(size_t size_bytes,lv_color_format_t color_format)648 static void * buf_malloc(size_t size_bytes, lv_color_format_t color_format)
649 {
650 LV_UNUSED(color_format);
651
652 /*Allocate larger memory to be sure it can be aligned as needed*/
653 size_bytes += LV_DRAW_BUF_ALIGN - 1;
654 return lv_malloc(size_bytes);
655 }
656
buf_free(void * buf)657 static void buf_free(void * buf)
658 {
659 lv_free(buf);
660 }
661
buf_align(void * buf,lv_color_format_t color_format)662 static void * buf_align(void * buf, lv_color_format_t color_format)
663 {
664 LV_UNUSED(color_format);
665
666 uint8_t * buf_u8 = buf;
667 if(buf_u8) {
668 buf_u8 = (uint8_t *)LV_ROUND_UP((lv_uintptr_t)buf_u8, LV_DRAW_BUF_ALIGN);
669 }
670 return buf_u8;
671 }
672
width_to_stride(uint32_t w,lv_color_format_t color_format)673 static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format)
674 {
675 uint32_t width_byte;
676 width_byte = w * lv_color_format_get_bpp(color_format);
677 width_byte = (width_byte + 7) >> 3; /*Round up*/
678
679 return LV_ROUND_UP(width_byte, LV_DRAW_BUF_STRIDE_ALIGN);
680 }
681
draw_buf_malloc(const lv_draw_buf_handlers_t * handlers,size_t size_bytes,lv_color_format_t color_format)682 static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handlers, size_t size_bytes,
683 lv_color_format_t color_format)
684 {
685 if(handlers->buf_malloc_cb) return handlers->buf_malloc_cb(size_bytes, color_format);
686 else return NULL;
687 }
688
draw_buf_free(const lv_draw_buf_handlers_t * handlers,void * buf)689 static void draw_buf_free(const lv_draw_buf_handlers_t * handlers, void * buf)
690 {
691 if(handlers->buf_free_cb)
692 handlers->buf_free_cb(buf);
693 }
694
695 /**
696 * For given width, height, color format, and stride, calculate the size needed for a new draw buffer.
697 */
_calculate_draw_buf_size(uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)698 static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
699 {
700 uint32_t size;
701
702 if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
703
704 size = stride * h;
705 if(cf == LV_COLOR_FORMAT_RGB565A8) {
706 size += (stride / 2) * h; /*A8 mask*/
707 }
708 else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
709 /*@todo we have to include palette right before image data*/
710 size += LV_COLOR_INDEXED_PALETTE_SIZE(cf) * 4;
711 }
712
713 return size;
714 }
715
draw_buf_get_full_area(const lv_draw_buf_t * draw_buf,lv_area_t * full_area)716 static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area)
717 {
718 const lv_image_header_t * header = &draw_buf->header;
719 lv_area_set(full_area, 0, 0, header->w - 1, header->h - 1);
720 }
721