1 /**
2  * @file lv_draw_sw.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sw_private.h"
10 #include "../lv_draw_private.h"
11 #if LV_USE_DRAW_SW
12 
13 #include "../../core/lv_refr.h"
14 #include "../../display/lv_display_private.h"
15 #include "../../stdlib/lv_string.h"
16 #include "../../core/lv_global.h"
17 
18 #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
19     #if LV_USE_THORVG_EXTERNAL
20         #include <thorvg_capi.h>
21     #else
22         #include "../../libs/thorvg/thorvg_capi.h"
23     #endif
24 #endif
25 
26 #if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_HELIUM
27     #include "arm2d/lv_draw_sw_helium.h"
28 #elif LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_CUSTOM
29     #include LV_DRAW_SW_ASM_CUSTOM_INCLUDE
30 #endif
31 
32 #if LV_DRAW_SW_DRAW_UNIT_CNT > 1 && LV_USE_OS == LV_OS_NONE
33     #error "OS support is required when more than one SW rendering units are enabled"
34 #endif
35 
36 /*********************
37  *      DEFINES
38  *********************/
39 #define DRAW_UNIT_ID_SW     1
40 
41 /**********************
42  *      TYPEDEFS
43  **********************/
44 
45 /**********************
46  *  STATIC PROTOTYPES
47  **********************/
48 #if LV_USE_OS
49     static void render_thread_cb(void * ptr);
50 #endif
51 
52 static void execute_drawing(lv_draw_sw_unit_t * u);
53 
54 static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
55 static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
56 static int32_t lv_draw_sw_delete(lv_draw_unit_t * draw_unit);
57 
58 /**********************
59  *  STATIC VARIABLES
60  **********************/
61 #define _draw_info LV_GLOBAL_DEFAULT()->draw_info
62 
63 /**********************
64  *      MACROS
65  **********************/
66 
67 /**********************
68  *   GLOBAL FUNCTIONS
69  **********************/
70 
lv_draw_sw_init(void)71 void lv_draw_sw_init(void)
72 {
73 
74 #if LV_DRAW_SW_COMPLEX == 1
75     lv_draw_sw_mask_init();
76 #endif
77 
78     uint32_t i;
79     for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) {
80         lv_draw_sw_unit_t * draw_sw_unit = lv_draw_create_unit(sizeof(lv_draw_sw_unit_t));
81         draw_sw_unit->base_unit.dispatch_cb = dispatch;
82         draw_sw_unit->base_unit.evaluate_cb = evaluate;
83         draw_sw_unit->idx = i;
84         draw_sw_unit->base_unit.delete_cb = LV_USE_OS ? lv_draw_sw_delete : NULL;
85         draw_sw_unit->base_unit.name = "SW";
86 
87 #if LV_USE_OS
88         lv_thread_init(&draw_sw_unit->thread, "swdraw", LV_THREAD_PRIO_HIGH, render_thread_cb, LV_DRAW_THREAD_STACK_SIZE,
89                        draw_sw_unit);
90 #endif
91     }
92 
93 #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
94     tvg_engine_init(TVG_ENGINE_SW, 0);
95 #endif
96 }
97 
lv_draw_sw_deinit(void)98 void lv_draw_sw_deinit(void)
99 {
100 #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
101     tvg_engine_term(TVG_ENGINE_SW);
102 #endif
103 
104 #if LV_DRAW_SW_COMPLEX == 1
105     lv_draw_sw_mask_deinit();
106 #endif
107 }
108 
lv_draw_sw_delete(lv_draw_unit_t * draw_unit)109 static int32_t lv_draw_sw_delete(lv_draw_unit_t * draw_unit)
110 {
111 #if LV_USE_OS
112     lv_draw_sw_unit_t * draw_sw_unit = (lv_draw_sw_unit_t *) draw_unit;
113 
114     LV_LOG_INFO("cancel software rendering thread");
115     draw_sw_unit->exit_status = true;
116 
117     if(draw_sw_unit->inited) {
118         lv_thread_sync_signal(&draw_sw_unit->sync);
119     }
120 
121     return lv_thread_delete(&draw_sw_unit->thread);
122 #else
123     LV_UNUSED(draw_unit);
124     return 0;
125 #endif
126 }
127 
128 /**********************
129  *   STATIC FUNCTIONS
130  **********************/
execute_drawing_unit(lv_draw_sw_unit_t * u)131 static inline void execute_drawing_unit(lv_draw_sw_unit_t * u)
132 {
133     execute_drawing(u);
134 
135     u->task_act->state = LV_DRAW_TASK_STATE_READY;
136     u->task_act = NULL;
137 
138     /*The draw unit is free now. Request a new dispatching as it can get a new task*/
139     lv_draw_dispatch_request();
140 }
141 
evaluate(lv_draw_unit_t * draw_unit,lv_draw_task_t * task)142 static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
143 {
144     LV_UNUSED(draw_unit);
145 
146     switch(task->type) {
147         case LV_DRAW_TASK_TYPE_IMAGE:
148         case LV_DRAW_TASK_TYPE_LAYER: {
149                 lv_draw_image_dsc_t * draw_dsc = task->draw_dsc;
150 
151                 /* not support skew */
152                 if(draw_dsc->skew_x != 0 || draw_dsc->skew_y != 0) {
153                     return 0;
154                 }
155 
156                 bool masked = draw_dsc->bitmap_mask_src != NULL;
157 
158                 lv_color_format_t cf = draw_dsc->header.cf;
159                 if(masked && (cf == LV_COLOR_FORMAT_A8 || cf == LV_COLOR_FORMAT_RGB565A8)) {
160                     return 0;
161                 }
162 
163                 if(cf >= LV_COLOR_FORMAT_PROPRIETARY_START) {
164                     return 0;
165                 }
166             }
167             break;
168         default:
169             break;
170     }
171 
172     if(task->preference_score >= 100) {
173         task->preference_score = 100;
174         task->preferred_draw_unit_id = DRAW_UNIT_ID_SW;
175     }
176 
177     return 0;
178 }
179 
dispatch(lv_draw_unit_t * draw_unit,lv_layer_t * layer)180 static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
181 {
182     LV_PROFILER_DRAW_BEGIN;
183     lv_draw_sw_unit_t * draw_sw_unit = (lv_draw_sw_unit_t *) draw_unit;
184 
185     /*Return immediately if it's busy with draw task*/
186     if(draw_sw_unit->task_act) {
187         LV_PROFILER_DRAW_END;
188         return 0;
189     }
190 
191     lv_draw_task_t * t = NULL;
192     t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_SW);
193     if(t == NULL) {
194         LV_PROFILER_DRAW_END;
195         return LV_DRAW_UNIT_IDLE;  /*Couldn't start rendering*/
196     }
197 
198     void * buf = lv_draw_layer_alloc_buf(layer);
199     if(buf == NULL) {
200         LV_PROFILER_DRAW_END;
201         return LV_DRAW_UNIT_IDLE;  /*Couldn't start rendering*/
202     }
203 
204     t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
205     draw_sw_unit->base_unit.target_layer = layer;
206     draw_sw_unit->base_unit.clip_area = &t->clip_area;
207     draw_sw_unit->task_act = t;
208 
209 #if LV_USE_OS
210     /*Let the render thread work*/
211     if(draw_sw_unit->inited) lv_thread_sync_signal(&draw_sw_unit->sync);
212 #else
213     execute_drawing_unit(draw_sw_unit);
214 #endif
215     LV_PROFILER_DRAW_END;
216     return 1;
217 }
218 
219 #if LV_USE_OS
render_thread_cb(void * ptr)220 static void render_thread_cb(void * ptr)
221 {
222     lv_draw_sw_unit_t * u = ptr;
223 
224     lv_thread_sync_init(&u->sync);
225     u->inited = true;
226 
227     while(1) {
228         while(u->task_act == NULL) {
229             if(u->exit_status) {
230                 break;
231             }
232             lv_thread_sync_wait(&u->sync);
233         }
234 
235         if(u->exit_status) {
236             LV_LOG_INFO("ready to exit software rendering thread");
237             break;
238         }
239 
240         execute_drawing_unit(u);
241     }
242 
243     u->inited = false;
244     lv_thread_sync_delete(&u->sync);
245     LV_LOG_INFO("exit software rendering thread");
246 }
247 #endif
248 
execute_drawing(lv_draw_sw_unit_t * u)249 static void execute_drawing(lv_draw_sw_unit_t * u)
250 {
251     LV_PROFILER_DRAW_BEGIN;
252     /*Render the draw task*/
253     lv_draw_task_t * t = u->task_act;
254     switch(t->type) {
255         case LV_DRAW_TASK_TYPE_FILL:
256             lv_draw_sw_fill((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
257             break;
258         case LV_DRAW_TASK_TYPE_BORDER:
259             lv_draw_sw_border((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
260             break;
261         case LV_DRAW_TASK_TYPE_BOX_SHADOW:
262             lv_draw_sw_box_shadow((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
263             break;
264         case LV_DRAW_TASK_TYPE_LETTER:
265             lv_draw_sw_letter((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
266             break;
267         case LV_DRAW_TASK_TYPE_LABEL:
268             lv_draw_sw_label((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
269             break;
270         case LV_DRAW_TASK_TYPE_IMAGE:
271             lv_draw_sw_image((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
272             break;
273         case LV_DRAW_TASK_TYPE_ARC:
274             lv_draw_sw_arc((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
275             break;
276         case LV_DRAW_TASK_TYPE_LINE:
277             lv_draw_sw_line((lv_draw_unit_t *)u, t->draw_dsc);
278             break;
279         case LV_DRAW_TASK_TYPE_TRIANGLE:
280             lv_draw_sw_triangle((lv_draw_unit_t *)u, t->draw_dsc);
281             break;
282         case LV_DRAW_TASK_TYPE_LAYER:
283             lv_draw_sw_layer((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
284             break;
285         case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
286             lv_draw_sw_mask_rect((lv_draw_unit_t *)u, t->draw_dsc, &t->area);
287             break;
288 #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
289         case LV_DRAW_TASK_TYPE_VECTOR:
290             lv_draw_sw_vector((lv_draw_unit_t *)u, t->draw_dsc);
291             break;
292 #endif
293         default:
294             break;
295     }
296 
297 #if LV_USE_PARALLEL_DRAW_DEBUG
298     /*Layers manage it for themselves*/
299     if(t->type != LV_DRAW_TASK_TYPE_LAYER) {
300         lv_area_t draw_area;
301         if(!lv_area_intersect(&draw_area, &t->area, u->base_unit.clip_area)) return;
302 
303         int32_t idx = 0;
304         lv_draw_unit_t * draw_unit_tmp = _draw_info.unit_head;
305         while(draw_unit_tmp != (lv_draw_unit_t *)u) {
306             draw_unit_tmp = draw_unit_tmp->next;
307             idx++;
308         }
309         lv_draw_fill_dsc_t fill_dsc;
310         lv_draw_fill_dsc_init(&fill_dsc);
311         fill_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
312         fill_dsc.opa = LV_OPA_10;
313         lv_draw_sw_fill((lv_draw_unit_t *)u, &fill_dsc, &draw_area);
314 
315         lv_draw_border_dsc_t border_dsc;
316         lv_draw_border_dsc_init(&border_dsc);
317         border_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
318         border_dsc.opa = LV_OPA_60;
319         border_dsc.width = 1;
320         lv_draw_sw_border((lv_draw_unit_t *)u, &border_dsc, &draw_area);
321 
322         lv_point_t txt_size;
323         lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
324 
325         lv_area_t txt_area;
326         txt_area.x1 = draw_area.x1;
327         txt_area.y1 = draw_area.y1;
328         txt_area.x2 = draw_area.x1 + txt_size.x - 1;
329         txt_area.y2 = draw_area.y1 + txt_size.y - 1;
330 
331         lv_draw_fill_dsc_init(&fill_dsc);
332         fill_dsc.color = lv_color_white();
333         lv_draw_sw_fill((lv_draw_unit_t *)u, &fill_dsc, &txt_area);
334 
335         char buf[8];
336         lv_snprintf(buf, sizeof(buf), "%d", idx);
337         lv_draw_label_dsc_t label_dsc;
338         lv_draw_label_dsc_init(&label_dsc);
339         label_dsc.color = lv_color_black();
340         label_dsc.text = buf;
341         lv_draw_sw_label((lv_draw_unit_t *)u, &label_dsc, &txt_area);
342     }
343 #endif
344     LV_PROFILER_DRAW_END;
345 }
346 
347 #endif /*LV_USE_DRAW_SW*/
348