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