1 /**
2 * @file lv_hal_disp.c
3 *
4 * @description HAL layer for display driver
5 *
6 */
7
8 /*********************
9 * INCLUDES
10 *********************/
11 #include <stdint.h>
12 #include <stddef.h>
13 #include "lv_hal.h"
14 #include "../misc/lv_mem.h"
15 #include "../misc/lv_gc.h"
16 #include "../misc/lv_assert.h"
17 #include "../core/lv_obj.h"
18 #include "../core/lv_refr.h"
19 #include "../core/lv_theme.h"
20 #include "../draw/sdl/lv_draw_sdl.h"
21 #include "../draw/sw/lv_draw_sw.h"
22 #include "../draw/sdl/lv_draw_sdl.h"
23 #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h"
24 #include "../draw/swm341_dma2d/lv_gpu_swm341_dma2d.h"
25 #include "../draw/arm2d/lv_gpu_arm2d.h"
26 #include "../draw/nxp/vglite/lv_draw_vglite.h"
27 #include "../draw/nxp/pxp/lv_draw_pxp.h"
28
29 #if LV_USE_THEME_DEFAULT
30 #include "../extra/themes/default/lv_theme_default.h"
31 #endif
32
33 /*********************
34 * DEFINES
35 *********************/
36
37 /**********************
38 * TYPEDEFS
39 **********************/
40
41 /**********************
42 * STATIC PROTOTYPES
43 **********************/
44 static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data);
45
46 static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x,
47 lv_coord_t y,
48 lv_color_t color, lv_opa_t opa);
49
50 static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
51 lv_color_t color, lv_opa_t opa);
52
53 static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
54 lv_color_t color, lv_opa_t opa);
55
56 static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
57 lv_color_t color, lv_opa_t opa);
58
59 static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
60 lv_color_t color, lv_opa_t opa);
61
62 static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
63
64 /**********************
65 * STATIC VARIABLES
66 **********************/
67 static lv_disp_t * disp_def;
68
69 /**********************
70 * MACROS
71 **********************/
72
73 /**********************
74 * GLOBAL FUNCTIONS
75 **********************/
76
77 /**
78 * Initialize a display driver with default values.
79 * It is used to surly have known values in the fields ant not memory junk.
80 * After it you can set the fields.
81 * @param driver pointer to driver variable to initialize
82 */
lv_disp_drv_init(lv_disp_drv_t * driver)83 void lv_disp_drv_init(lv_disp_drv_t * driver)
84 {
85 lv_memset_00(driver, sizeof(lv_disp_drv_t));
86
87 driver->hor_res = 320;
88 driver->ver_res = 240;
89 driver->physical_hor_res = -1;
90 driver->physical_ver_res = -1;
91 driver->offset_x = 0;
92 driver->offset_y = 0;
93 driver->antialiasing = LV_COLOR_DEPTH > 8 ? 1 : 0;
94 driver->screen_transp = 0;
95 driver->dpi = LV_DPI_DEF;
96 driver->color_chroma_key = LV_COLOR_CHROMA_KEY;
97
98
99 #if LV_USE_GPU_STM32_DMA2D
100 driver->draw_ctx_init = lv_draw_stm32_dma2d_ctx_init;
101 driver->draw_ctx_deinit = lv_draw_stm32_dma2d_ctx_init;
102 driver->draw_ctx_size = sizeof(lv_draw_stm32_dma2d_ctx_t);
103 #elif LV_USE_GPU_SWM341_DMA2D
104 driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init;
105 driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_init;
106 driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t);
107 #elif LV_USE_GPU_NXP_VG_LITE
108 driver->draw_ctx_init = lv_draw_vglite_ctx_init;
109 driver->draw_ctx_deinit = lv_draw_vglite_ctx_deinit;
110 driver->draw_ctx_size = sizeof(lv_draw_vglite_ctx_t);
111 #elif LV_USE_GPU_NXP_PXP
112 driver->draw_ctx_init = lv_draw_pxp_ctx_init;
113 driver->draw_ctx_deinit = lv_draw_pxp_ctx_deinit;
114 driver->draw_ctx_size = sizeof(lv_draw_pxp_ctx_t);
115 #elif LV_USE_GPU_SDL
116 driver->draw_ctx_init = lv_draw_sdl_init_ctx;
117 driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx;
118 driver->draw_ctx_size = sizeof(lv_draw_sdl_ctx_t);
119 #elif LV_USE_GPU_ARM2D
120 driver->draw_ctx_init = lv_draw_arm2d_ctx_init;
121 driver->draw_ctx_deinit = lv_draw_arm2d_ctx_init;
122 driver->draw_ctx_size = sizeof(lv_draw_arm2d_ctx_t);
123 #else
124 driver->draw_ctx_init = lv_draw_sw_init_ctx;
125 driver->draw_ctx_deinit = lv_draw_sw_init_ctx;
126 driver->draw_ctx_size = sizeof(lv_draw_sw_ctx_t);
127 #endif
128
129 }
130
131 /**
132 * Initialize a display buffer
133 * @param draw_buf pointer `lv_disp_draw_buf_t` variable to initialize
134 * @param buf1 A buffer to be used by LVGL to draw the image.
135 * Always has to specified and can't be NULL.
136 * Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
137 * Or a memory address e.g. in external SRAM
138 * @param buf2 Optionally specify a second buffer to make image rendering and image flushing
139 * (sending to the display) parallel.
140 * In the `disp_drv->flush` you should use DMA or similar hardware to send
141 * the image to the display in the background.
142 * It lets LVGL to render next frame into the other buffer while previous is being
143 * sent. Set to `NULL` if unused.
144 * @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count.
145 */
lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf,void * buf1,void * buf2,uint32_t size_in_px_cnt)146 void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt)
147 {
148 lv_memset_00(draw_buf, sizeof(lv_disp_draw_buf_t));
149
150 draw_buf->buf1 = buf1;
151 draw_buf->buf2 = buf2;
152 draw_buf->buf_act = draw_buf->buf1;
153 draw_buf->size = size_in_px_cnt;
154 }
155
156 /**
157 * Register an initialized display driver.
158 * Automatically set the first display as active.
159 * @param driver pointer to an initialized 'lv_disp_drv_t' variable. Only its pointer is saved!
160 * @return pointer to the new display or NULL on error
161 */
lv_disp_drv_register(lv_disp_drv_t * driver)162 lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
163 {
164 lv_disp_t * disp = _lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll));
165 LV_ASSERT_MALLOC(disp);
166 if(!disp) {
167 return NULL;
168 }
169
170 /*Create a draw context if not created yet*/
171 if(driver->draw_ctx == NULL) {
172 lv_draw_ctx_t * draw_ctx = lv_mem_alloc(driver->draw_ctx_size);
173 LV_ASSERT_MALLOC(draw_ctx);
174 if(draw_ctx == NULL) return NULL;
175 driver->draw_ctx_init(driver, draw_ctx);
176 driver->draw_ctx = draw_ctx;
177 }
178
179 lv_memset_00(disp, sizeof(lv_disp_t));
180
181 disp->driver = driver;
182
183 disp->inv_en_cnt = 1;
184
185 lv_disp_t * disp_def_tmp = disp_def;
186 disp_def = disp; /*Temporarily change the default screen to create the default screens on the
187 new display*/
188 /*Create a refresh timer*/
189 disp->refr_timer = lv_timer_create(_lv_disp_refr_timer, LV_DISP_DEF_REFR_PERIOD, disp);
190 LV_ASSERT_MALLOC(disp->refr_timer);
191 if(disp->refr_timer == NULL) {
192 lv_mem_free(disp);
193 return NULL;
194 }
195
196 if(driver->full_refresh && driver->draw_buf->size < (uint32_t)driver->hor_res * driver->ver_res) {
197 driver->full_refresh = 0;
198 LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)");
199 }
200
201 disp->bg_color = lv_color_white();
202 #if LV_COLOR_SCREEN_TRANSP
203 disp->bg_opa = LV_OPA_TRANSP;
204 #else
205 disp->bg_opa = LV_OPA_COVER;
206 #endif
207
208 #if LV_USE_THEME_DEFAULT
209 if(lv_theme_default_is_inited() == false) {
210 disp->theme = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED),
211 LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
212 }
213 else {
214 disp->theme = lv_theme_default_get();
215 }
216 #endif
217
218 disp->act_scr = lv_obj_create(NULL); /*Create a default screen on the display*/
219 disp->top_layer = lv_obj_create(NULL); /*Create top layer on the display*/
220 disp->sys_layer = lv_obj_create(NULL); /*Create sys layer on the display*/
221 lv_obj_remove_style_all(disp->top_layer);
222 lv_obj_remove_style_all(disp->sys_layer);
223 lv_obj_clear_flag(disp->top_layer, LV_OBJ_FLAG_CLICKABLE);
224 lv_obj_clear_flag(disp->sys_layer, LV_OBJ_FLAG_CLICKABLE);
225
226 lv_obj_set_scrollbar_mode(disp->top_layer, LV_SCROLLBAR_MODE_OFF);
227 lv_obj_set_scrollbar_mode(disp->sys_layer, LV_SCROLLBAR_MODE_OFF);
228
229 lv_obj_invalidate(disp->act_scr);
230
231 disp_def = disp_def_tmp; /*Revert the default display*/
232 if(disp_def == NULL) disp_def = disp; /*Initialize the default display*/
233
234 lv_timer_ready(disp->refr_timer); /*Be sure the screen will be refreshed immediately on start up*/
235
236 return disp;
237 }
238
239 /**
240 * Update the driver in run time.
241 * @param disp pointer to a display. (return value of `lv_disp_drv_register`)
242 * @param new_drv pointer to the new driver
243 */
lv_disp_drv_update(lv_disp_t * disp,lv_disp_drv_t * new_drv)244 void lv_disp_drv_update(lv_disp_t * disp, lv_disp_drv_t * new_drv)
245 {
246 disp->driver = new_drv;
247
248 if(disp->driver->full_refresh &&
249 disp->driver->draw_buf->size < (uint32_t)disp->driver->hor_res * disp->driver->ver_res) {
250 disp->driver->full_refresh = 0;
251 LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)");
252 }
253
254 lv_coord_t w = lv_disp_get_hor_res(disp);
255 lv_coord_t h = lv_disp_get_ver_res(disp);
256 uint32_t i;
257 for(i = 0; i < disp->screen_cnt; i++) {
258 lv_area_t prev_coords;
259 lv_obj_get_coords(disp->screens[i], &prev_coords);
260 lv_area_set_width(&disp->screens[i]->coords, w);
261 lv_area_set_height(&disp->screens[i]->coords, h);
262 lv_event_send(disp->screens[i], LV_EVENT_SIZE_CHANGED, &prev_coords);
263 }
264
265 /*
266 * This method is usually called upon orientation change, thus the screen is now a
267 * different size.
268 * The object invalidated its previous area. That area is now out of the screen area
269 * so we reset all invalidated areas and invalidate the active screen's new area only.
270 */
271 lv_memset_00(disp->inv_areas, sizeof(disp->inv_areas));
272 lv_memset_00(disp->inv_area_joined, sizeof(disp->inv_area_joined));
273 disp->inv_p = 0;
274 if(disp->act_scr != NULL) lv_obj_invalidate(disp->act_scr);
275
276 lv_obj_tree_walk(NULL, invalidate_layout_cb, NULL);
277
278 if(disp->driver->drv_update_cb) disp->driver->drv_update_cb(disp->driver);
279 }
280
281 /**
282 * Remove a display
283 * @param disp pointer to display
284 */
lv_disp_remove(lv_disp_t * disp)285 void lv_disp_remove(lv_disp_t * disp)
286 {
287 bool was_default = false;
288 if(disp == lv_disp_get_default()) was_default = true;
289
290 /*Detach the input devices*/
291 lv_indev_t * indev;
292 indev = lv_indev_get_next(NULL);
293 while(indev) {
294 if(indev->driver->disp == disp) {
295 indev->driver->disp = NULL;
296 }
297 indev = lv_indev_get_next(indev);
298 }
299
300 /** delete screen and other obj */
301 if(disp->sys_layer) {
302 lv_obj_del(disp->sys_layer);
303 disp->sys_layer = NULL;
304 }
305 if(disp->top_layer) {
306 lv_obj_del(disp->top_layer);
307 disp->top_layer = NULL;
308 }
309 while(disp->screen_cnt != 0) {
310 /*Delete the screenst*/
311 lv_obj_del(disp->screens[0]);
312 }
313
314 _lv_ll_remove(&LV_GC_ROOT(_lv_disp_ll), disp);
315 if(disp->refr_timer) lv_timer_del(disp->refr_timer);
316 lv_mem_free(disp);
317
318 if(was_default) lv_disp_set_default(_lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)));
319 }
320
321 /**
322 * Set a default display. The new screens will be created on it by default.
323 * @param disp pointer to a display
324 */
lv_disp_set_default(lv_disp_t * disp)325 void lv_disp_set_default(lv_disp_t * disp)
326 {
327 disp_def = disp;
328 }
329
330 /**
331 * Get the default display
332 * @return pointer to the default display
333 */
lv_disp_get_default(void)334 lv_disp_t * lv_disp_get_default(void)
335 {
336 return disp_def;
337 }
338
339 /**
340 * Get the horizontal resolution of a display
341 * @param disp pointer to a display (NULL to use the default display)
342 * @return the horizontal resolution of the display
343 */
lv_disp_get_hor_res(lv_disp_t * disp)344 lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp)
345 {
346 if(disp == NULL) disp = lv_disp_get_default();
347
348 if(disp == NULL) {
349 return 0;
350 }
351 else {
352 switch(disp->driver->rotated) {
353 case LV_DISP_ROT_90:
354 case LV_DISP_ROT_270:
355 return disp->driver->ver_res;
356 default:
357 return disp->driver->hor_res;
358 }
359 }
360 }
361
362 /**
363 * Get the vertical resolution of a display
364 * @param disp pointer to a display (NULL to use the default display)
365 * @return the vertical resolution of the display
366 */
lv_disp_get_ver_res(lv_disp_t * disp)367 lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp)
368 {
369 if(disp == NULL) disp = lv_disp_get_default();
370
371 if(disp == NULL) {
372 return 0;
373 }
374 else {
375 switch(disp->driver->rotated) {
376 case LV_DISP_ROT_90:
377 case LV_DISP_ROT_270:
378 return disp->driver->hor_res;
379 default:
380 return disp->driver->ver_res;
381 }
382 }
383 }
384
385 /**
386 * Get the full / physical horizontal resolution of a display
387 * @param disp pointer to a display (NULL to use the default display)
388 * @return the full / physical horizontal resolution of the display
389 */
lv_disp_get_physical_hor_res(lv_disp_t * disp)390 lv_coord_t lv_disp_get_physical_hor_res(lv_disp_t * disp)
391 {
392 if(disp == NULL) disp = lv_disp_get_default();
393
394 if(disp == NULL) {
395 return 0;
396 }
397 else {
398 switch(disp->driver->rotated) {
399 case LV_DISP_ROT_90:
400 case LV_DISP_ROT_270:
401 return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res;
402 default:
403 return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res;
404 }
405 }
406 }
407
408 /**
409 * Get the full / physical vertical resolution of a display
410 * @param disp pointer to a display (NULL to use the default display)
411 * @return the full / physical vertical resolution of the display
412 */
lv_disp_get_physical_ver_res(lv_disp_t * disp)413 lv_coord_t lv_disp_get_physical_ver_res(lv_disp_t * disp)
414 {
415 if(disp == NULL) disp = lv_disp_get_default();
416
417 if(disp == NULL) {
418 return 0;
419 }
420 else {
421 switch(disp->driver->rotated) {
422 case LV_DISP_ROT_90:
423 case LV_DISP_ROT_270:
424 return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res;
425 default:
426 return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res;
427 }
428 }
429 }
430
431 /**
432 * Get the horizontal offset from the full / physical display
433 * @param disp pointer to a display (NULL to use the default display)
434 * @return the horizontal offset from the full / physical display
435 */
lv_disp_get_offset_x(lv_disp_t * disp)436 lv_coord_t lv_disp_get_offset_x(lv_disp_t * disp)
437 {
438 if(disp == NULL) disp = lv_disp_get_default();
439
440 if(disp == NULL) {
441 return 0;
442 }
443 else {
444 switch(disp->driver->rotated) {
445 case LV_DISP_ROT_90:
446 return disp->driver->offset_y;
447 case LV_DISP_ROT_180:
448 return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_x;
449 case LV_DISP_ROT_270:
450 return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_y;
451 default:
452 return disp->driver->offset_x;
453 }
454 }
455 }
456
457 /**
458 * Get the vertical offset from the full / physical display
459 * @param disp pointer to a display (NULL to use the default display)
460 * @return the horizontal offset from the full / physical display
461 */
lv_disp_get_offset_y(lv_disp_t * disp)462 lv_coord_t lv_disp_get_offset_y(lv_disp_t * disp)
463 {
464 if(disp == NULL) disp = lv_disp_get_default();
465
466 if(disp == NULL) {
467 return 0;
468 }
469 else {
470 switch(disp->driver->rotated) {
471 case LV_DISP_ROT_90:
472 return disp->driver->offset_x;
473 case LV_DISP_ROT_180:
474 return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_y;
475 case LV_DISP_ROT_270:
476 return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_x;
477 default:
478 return disp->driver->offset_y;
479 }
480 }
481 }
482
483 /**
484 * Get if anti-aliasing is enabled for a display or not
485 * @param disp pointer to a display (NULL to use the default display)
486 * @return true: anti-aliasing is enabled; false: disabled
487 */
lv_disp_get_antialiasing(lv_disp_t * disp)488 bool lv_disp_get_antialiasing(lv_disp_t * disp)
489 {
490 if(disp == NULL) disp = lv_disp_get_default();
491 if(disp == NULL) return false;
492
493 return disp->driver->antialiasing ? true : false;
494 }
495
496 /**
497 * Get the DPI of the display
498 * @param disp pointer to a display (NULL to use the default display)
499 * @return dpi of the display
500 */
lv_disp_get_dpi(const lv_disp_t * disp)501 lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp)
502 {
503 if(disp == NULL) disp = lv_disp_get_default();
504 if(disp == NULL) return LV_DPI_DEF; /*Do not return 0 because it might be a divider*/
505 return disp->driver->dpi;
506 }
507
508 /**
509 * Call in the display driver's `flush_cb` function when the flushing is finished
510 * @param disp_drv pointer to display driver in `flush_cb` where this function is called
511 */
lv_disp_flush_ready(lv_disp_drv_t * disp_drv)512 LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv)
513 {
514 disp_drv->draw_buf->flushing = 0;
515 disp_drv->draw_buf->flushing_last = 0;
516 }
517
518 /**
519 * Tell if it's the last area of the refreshing process.
520 * Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed.
521 * @param disp_drv pointer to display driver
522 * @return true: it's the last area to flush; false: there are other areas too which will be refreshed soon
523 */
lv_disp_flush_is_last(lv_disp_drv_t * disp_drv)524 LV_ATTRIBUTE_FLUSH_READY bool lv_disp_flush_is_last(lv_disp_drv_t * disp_drv)
525 {
526 return disp_drv->draw_buf->flushing_last;
527 }
528
529 /**
530 * Get the next display.
531 * @param disp pointer to the current display. NULL to initialize.
532 * @return the next display or NULL if no more. Give the first display when the parameter is NULL
533 */
lv_disp_get_next(lv_disp_t * disp)534 lv_disp_t * lv_disp_get_next(lv_disp_t * disp)
535 {
536 if(disp == NULL)
537 return _lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll));
538 else
539 return _lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp);
540 }
541
542 /**
543 * Get the internal buffer of a display
544 * @param disp pointer to a display
545 * @return pointer to the internal buffers
546 */
lv_disp_get_draw_buf(lv_disp_t * disp)547 lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp)
548 {
549 return disp->driver->draw_buf;
550 }
551
552 /**
553 * Set the rotation of this display.
554 * @param disp pointer to a display (NULL to use the default display)
555 * @param rotation rotation angle
556 */
lv_disp_set_rotation(lv_disp_t * disp,lv_disp_rot_t rotation)557 void lv_disp_set_rotation(lv_disp_t * disp, lv_disp_rot_t rotation)
558 {
559 if(disp == NULL) disp = lv_disp_get_default();
560 if(disp == NULL) return;
561
562 disp->driver->rotated = rotation;
563 lv_disp_drv_update(disp, disp->driver);
564 }
565
566 /**
567 * Get the current rotation of this display.
568 * @param disp pointer to a display (NULL to use the default display)
569 * @return rotation angle
570 */
lv_disp_get_rotation(lv_disp_t * disp)571 lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp)
572 {
573 if(disp == NULL) disp = lv_disp_get_default();
574 if(disp == NULL) return LV_DISP_ROT_NONE;
575 return disp->driver->rotated;
576 }
577
lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv,lv_img_cf_t cf)578 void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf)
579 {
580 switch(cf) {
581 case LV_IMG_CF_TRUE_COLOR_ALPHA:
582 disp_drv->set_px_cb = set_px_true_color_alpha;
583 break;
584 case LV_IMG_CF_ALPHA_1BIT:
585 disp_drv->set_px_cb = set_px_cb_alpha1;
586 break;
587 case LV_IMG_CF_ALPHA_2BIT:
588 disp_drv->set_px_cb = set_px_cb_alpha2;
589 break;
590 case LV_IMG_CF_ALPHA_4BIT:
591 disp_drv->set_px_cb = set_px_cb_alpha4;
592 break;
593 case LV_IMG_CF_ALPHA_8BIT:
594 disp_drv->set_px_cb = set_px_cb_alpha8;
595 break;
596 default:
597 disp_drv->set_px_cb = NULL;
598 }
599 }
600
601 /**********************
602 * STATIC FUNCTIONS
603 **********************/
604
invalidate_layout_cb(lv_obj_t * obj,void * user_data)605 static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data)
606 {
607 LV_UNUSED(user_data);
608 lv_obj_mark_layout_as_dirty(obj);
609 return LV_OBJ_TREE_WALK_NEXT;
610 }
611
set_px_cb_alpha1(lv_disp_drv_t * disp_drv,uint8_t * buf,lv_coord_t buf_w,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)612 static void set_px_cb_alpha1(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
613 lv_color_t color, lv_opa_t opa)
614 {
615 (void) disp_drv; /*Unused*/
616
617 if(opa <= LV_OPA_MIN) return;
618 lv_img_dsc_t d;
619 d.data = buf;
620 d.header.w = buf_w;
621 d.header.cf = LV_IMG_CF_ALPHA_1BIT;
622
623 set_px_alpha_generic(&d, x, y, color, opa);
624 }
625
set_px_cb_alpha2(lv_disp_drv_t * disp_drv,uint8_t * buf,lv_coord_t buf_w,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)626 static void set_px_cb_alpha2(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
627 lv_color_t color, lv_opa_t opa)
628 {
629 (void) disp_drv; /*Unused*/
630
631 if(opa <= LV_OPA_MIN) return;
632 lv_img_dsc_t d;
633 d.data = buf;
634 d.header.w = buf_w;
635 d.header.cf = LV_IMG_CF_ALPHA_2BIT;
636
637 set_px_alpha_generic(&d, x, y, color, opa);
638 }
639
set_px_cb_alpha4(lv_disp_drv_t * disp_drv,uint8_t * buf,lv_coord_t buf_w,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)640 static void set_px_cb_alpha4(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
641 lv_color_t color, lv_opa_t opa)
642 {
643 (void) disp_drv; /*Unused*/
644
645 if(opa <= LV_OPA_MIN) return;
646 lv_img_dsc_t d;
647 d.data = buf;
648 d.header.w = buf_w;
649 d.header.cf = LV_IMG_CF_ALPHA_4BIT;
650
651 set_px_alpha_generic(&d, x, y, color, opa);
652 }
653
set_px_cb_alpha8(lv_disp_drv_t * disp_drv,uint8_t * buf,lv_coord_t buf_w,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)654 static void set_px_cb_alpha8(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
655 lv_color_t color, lv_opa_t opa)
656 {
657 (void) disp_drv; /*Unused*/
658
659 if(opa <= LV_OPA_MIN) return;
660 lv_img_dsc_t d;
661 d.data = buf;
662 d.header.w = buf_w;
663 d.header.cf = LV_IMG_CF_ALPHA_8BIT;
664
665 set_px_alpha_generic(&d, x, y, color, opa);
666 }
667
set_px_alpha_generic(lv_img_dsc_t * d,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)668 static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
669 {
670 d->header.always_zero = 0;
671 d->header.h = 1; /*Doesn't matter*/
672
673 uint8_t br = lv_color_brightness(color);
674 if(opa < LV_OPA_MAX) {
675 uint8_t bg = lv_img_buf_get_px_alpha(d, x, y);
676 br = (uint16_t)((uint16_t)br * opa + (bg * (255 - opa))) >> 8;
677 }
678
679 lv_img_buf_set_px_alpha(d, x, y, br);
680 }
681
set_px_true_color_alpha(lv_disp_drv_t * disp_drv,uint8_t * buf,lv_coord_t buf_w,lv_coord_t x,lv_coord_t y,lv_color_t color,lv_opa_t opa)682 static void set_px_true_color_alpha(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w,
683 lv_coord_t x, lv_coord_t y,
684 lv_color_t color, lv_opa_t opa)
685 {
686 (void) disp_drv; /*Unused*/
687
688 uint8_t * buf_px = buf + (buf_w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE);
689
690 lv_color_t bg_color;
691 lv_color_t res_color;
692 lv_opa_t bg_opa = buf_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
693 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
694 bg_color.full = buf_px[0];
695 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
696 if(buf_px[1] <= LV_OPA_MIN) return;
697 buf_px[0] = res_color.full;
698 #elif LV_COLOR_DEPTH == 16
699 bg_color.full = buf_px[0] + (buf_px[1] << 8);
700 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
701 if(buf_px[2] <= LV_OPA_MIN) return;
702 buf_px[0] = res_color.full & 0xff;
703 buf_px[1] = res_color.full >> 8;
704 #elif LV_COLOR_DEPTH == 32
705 bg_color = *((lv_color_t *)buf_px);
706 lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[3]);
707 if(buf_px[3] <= LV_OPA_MIN) return;
708 buf_px[0] = res_color.ch.blue;
709 buf_px[1] = res_color.ch.green;
710 buf_px[2] = res_color.ch.red;
711 #endif
712
713 }
714