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