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