diff --git a/src/draw/dma2d/lv_draw_dma2d.c b/src/draw/dma2d/lv_draw_dma2d.c index 01b7d5498d..1cf966117d 100644 --- a/src/draw/dma2d/lv_draw_dma2d.c +++ b/src/draw/dma2d/lv_draw_dma2d.c @@ -353,7 +353,7 @@ static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer) #endif } - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_DMA2D); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DMA2D); if(t == NULL) { return LV_DRAW_UNIT_IDLE; } diff --git a/src/draw/lv_draw.c b/src/draw/lv_draw.c index cef1429b09..6e2729184f 100644 --- a/src/draw/lv_draw.c +++ b/src/draw/lv_draw.c @@ -32,7 +32,8 @@ * STATIC PROTOTYPES **********************/ static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check); -static void lv_cleanup_task(lv_draw_task_t * t, lv_display_t * disp); +static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp); +static lv_draw_task_t * get_first_available_task(lv_layer_t * layer); #if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO static inline uint32_t get_layer_size_kb(uint32_t size_byte) @@ -231,7 +232,7 @@ bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer) while(t) { t_next = t->next; if(t->state == LV_DRAW_TASK_STATE_READY) { - lv_cleanup_task(t, disp); + cleanup_task(t, disp); if(t_prev != NULL) t_prev->next = t_next; else @@ -309,37 +310,20 @@ uint32_t lv_draw_get_unit_count(void) return _draw_info.unit_cnt; } +lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id) +{ + if(_draw_info.unit_cnt == 1) { + return get_first_available_task(layer); + } + else { + return lv_draw_get_next_available_task(layer, t_prev, draw_unit_id); + } +} + lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id) { LV_PROFILER_DRAW_BEGIN; - /* If there is only 1 draw unit the task can be consumed linearly as - * they are added in the correct order. However, it can happen that - * there is a `LV_DRAW_TASK_TYPE_LAYER` which can be blended only when - * all its tasks are ready. As other areas might be on top of that - * layer-to-blend don't skip it. Instead stop there, so that the - * draw tasks of that layer can be consumed and can be finished. - * After that this layer-to-blenf will have `LV_DRAW_TASK_STATE_QUEUED` - * so it can be blended normally.*/ - if(_draw_info.unit_cnt <= 1) { - lv_draw_task_t * t = layer->draw_task_head; - while(t) { - /*Not queued yet, leave this layer while the first task will be queued*/ - if(t->state != LV_DRAW_TASK_STATE_QUEUED) { - t = NULL; - break; - } - /*It's a supported and queued task, process it*/ - else { - break; - } - t = t->next; - } - LV_PROFILER_DRAW_END; - return t; - } - - /*Handle the case of multiply draw units*/ /*If the first task is screen sized, there cannot be independent areas*/ if(layer->draw_task_head) { @@ -554,7 +538,7 @@ static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check) * @param t pointer to a draw task * @param disp pointer to a display on which the task was drawn */ -static void lv_cleanup_task(lv_draw_task_t * t, lv_display_t * disp) +static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp) { LV_PROFILER_DRAW_BEGIN; /*If it was layer drawing free the layer too*/ @@ -607,3 +591,32 @@ static void lv_cleanup_task(lv_draw_task_t * t, lv_display_t * disp) lv_free(t); LV_PROFILER_DRAW_END; } + +static lv_draw_task_t * get_first_available_task(lv_layer_t * layer) +{ + LV_PROFILER_DRAW_BEGIN; + /* If there is only 1 draw unit the task can be consumed linearly as + * they are added in the correct order. However, it can happen that + * there is a `LV_DRAW_TASK_TYPE_LAYER` which can be blended only when + * all its tasks are ready. As other areas might be on top of that + * layer-to-blend don't skip it. Instead stop there, so that the + * draw tasks of that layer can be consumed and can be finished. + * After that this layer-to-blenf will have `LV_DRAW_TASK_STATE_QUEUED` + * so it can be blended normally.*/ + lv_draw_task_t * t = layer->draw_task_head; + while(t) { + /*Not queued yet, leave this layer while the first task is queued*/ + if(t->state != LV_DRAW_TASK_STATE_QUEUED) { + t = NULL; + break; + } + /*It's a supported and queued task, process it*/ + else { + break; + } + t = t->next; + } + + LV_PROFILER_DRAW_END; + return t; +} diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h index 64abc38c08..b238e3a929 100644 --- a/src/draw/lv_draw.h +++ b/src/draw/lv_draw.h @@ -199,11 +199,21 @@ void lv_draw_dispatch_request(void); uint32_t lv_draw_get_unit_count(void); /** - * Find and available draw task - * @param layer the draw ctx to search in + * If there is only one draw unit check the first draw task if it's available. + * If there are multiple draw units call `lv_draw_get_next_available_task` to find a task. + * @param layer the draw layer to search in * @param t_prev continue searching from this task * @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE` - * @return tan available draw task or NULL if there is no any + * @return an available draw task or NULL if there is not any + */ +lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id); + +/** + * Find and available draw task + * @param layer the draw layer to search in + * @param t_prev continue searching from this task + * @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE` + * @return an available draw task or NULL if there is not any */ lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id); diff --git a/src/draw/nema_gfx/lv_draw_nema_gfx.c b/src/draw/nema_gfx/lv_draw_nema_gfx.c index 79834d2ee4..f07a059e59 100644 --- a/src/draw/nema_gfx/lv_draw_nema_gfx.c +++ b/src/draw/nema_gfx/lv_draw_nema_gfx.c @@ -263,7 +263,7 @@ static int32_t nema_gfx_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 0; /* Try to get an ready to draw. */ - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_NEMA_GFX); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_NEMA_GFX); /* Return 0 is no selection, some tasks can be supported by other units. */ if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_NEMA_GFX) diff --git a/src/draw/nxp/g2d/lv_draw_g2d.c b/src/draw/nxp/g2d/lv_draw_g2d.c index 9fa489fdb0..73afe27474 100644 --- a/src/draw/nxp/g2d/lv_draw_g2d.c +++ b/src/draw/nxp/g2d/lv_draw_g2d.c @@ -194,7 +194,7 @@ static int32_t _g2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 0; /* Try to get an ready to draw. */ - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_G2D); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_G2D); if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_G2D) return LV_DRAW_UNIT_IDLE; @@ -314,4 +314,4 @@ static void _g2d_render_thread_cb(void * ptr) } #endif -#endif /*LV_USE_DRAW_G2D*/ \ No newline at end of file +#endif /*LV_USE_DRAW_G2D*/ diff --git a/src/draw/nxp/pxp/lv_draw_pxp.c b/src/draw/nxp/pxp/lv_draw_pxp.c index ce6e8e7cf8..6332ba7f69 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp.c +++ b/src/draw/nxp/pxp/lv_draw_pxp.c @@ -323,7 +323,7 @@ static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 0; /* Try to get an ready to draw. */ - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_PXP); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_PXP); if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_PXP) return LV_DRAW_UNIT_IDLE; diff --git a/src/draw/nxp/vglite/lv_draw_vglite.c b/src/draw/nxp/vglite/lv_draw_vglite.c index 722435f25e..51b0e77ffc 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite.c +++ b/src/draw/nxp/vglite/lv_draw_vglite.c @@ -300,7 +300,7 @@ static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 0; /* Try to get an ready to draw. */ - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_VGLITE); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_VGLITE); if(t == NULL) return LV_DRAW_UNIT_IDLE; diff --git a/src/draw/opengles/lv_draw_opengles.c b/src/draw/opengles/lv_draw_opengles.c index ff792e8712..c5fc17a304 100644 --- a/src/draw/opengles/lv_draw_opengles.c +++ b/src/draw/opengles/lv_draw_opengles.c @@ -178,7 +178,7 @@ static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) if(draw_opengles_unit->task_act) return 0; lv_draw_task_t * t = NULL; - t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_OPENGLES); + t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_OPENGLES); if(t == NULL) return -1; unsigned int texture = layer_get_texture(layer); diff --git a/src/draw/renesas/dave2d/lv_draw_dave2d.c b/src/draw/renesas/dave2d/lv_draw_dave2d.c index 13ed0c559b..f4a6430c69 100644 --- a/src/draw/renesas/dave2d/lv_draw_dave2d.c +++ b/src/draw/renesas/dave2d/lv_draw_dave2d.c @@ -357,10 +357,10 @@ static int32_t lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * if(draw_dave2d_unit->task_act) return 0; lv_draw_task_t * t = NULL; - t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D); + t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D); while(t && t->preferred_draw_unit_id != DRAW_UNIT_ID_DAVE2D) { t->state = LV_DRAW_TASK_STATE_READY; - t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D); + t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D); } if(t == NULL) { diff --git a/src/draw/sdl/lv_draw_sdl.c b/src/draw/sdl/lv_draw_sdl.c index e0eef6fc67..01dc03006e 100644 --- a/src/draw/sdl/lv_draw_sdl.c +++ b/src/draw/sdl/lv_draw_sdl.c @@ -142,7 +142,7 @@ static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) if(draw_sdl_unit->task_act) return 0; lv_draw_task_t * t = NULL; - t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_SDL); + t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_SDL); if(t == NULL) return -1; lv_display_t * disp = lv_refr_get_disp_refreshing(); diff --git a/src/draw/sw/lv_draw_sw.c b/src/draw/sw/lv_draw_sw.c index 4156275124..2747a63041 100644 --- a/src/draw/sw/lv_draw_sw.c +++ b/src/draw/sw/lv_draw_sw.c @@ -49,11 +49,14 @@ static void render_thread_cb(void * ptr); #endif -static void execute_drawing(lv_draw_sw_unit_t * u); +static void execute_drawing(lv_draw_task_t * t); static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer); static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); static int32_t lv_draw_sw_delete(lv_draw_unit_t * draw_unit); +#if LV_USE_PARALLEL_DRAW_DEBUG + static void parallel_debug_draw(lv_draw_task_t * t, uint32_t idx); +#endif /********************** * STATIC VARIABLES @@ -75,19 +78,22 @@ void lv_draw_sw_init(void) lv_draw_sw_mask_init(); #endif - uint32_t i; - for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) { - lv_draw_sw_unit_t * draw_sw_unit = lv_draw_create_unit(sizeof(lv_draw_sw_unit_t)); - draw_sw_unit->base_unit.dispatch_cb = dispatch; - draw_sw_unit->base_unit.evaluate_cb = evaluate; - draw_sw_unit->base_unit.delete_cb = LV_USE_OS ? lv_draw_sw_delete : NULL; - draw_sw_unit->base_unit.name = "SW"; + lv_draw_sw_unit_t * draw_sw_unit = lv_draw_create_unit(sizeof(lv_draw_sw_unit_t)); + draw_sw_unit->base_unit.dispatch_cb = dispatch; + draw_sw_unit->base_unit.evaluate_cb = evaluate; + draw_sw_unit->base_unit.delete_cb = LV_USE_OS ? lv_draw_sw_delete : NULL; + draw_sw_unit->base_unit.name = "SW"; #if LV_USE_OS - lv_thread_init(&draw_sw_unit->thread, "swdraw", LV_THREAD_PRIO_HIGH, render_thread_cb, LV_DRAW_THREAD_STACK_SIZE, - draw_sw_unit); -#endif + uint32_t i; + for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) { + lv_draw_sw_thread_dsc_t * thread_dsc = &draw_sw_unit->thread_dscs[i]; + thread_dsc->idx = i; + thread_dsc->draw_unit = (void *) draw_sw_unit; + lv_thread_init(&thread_dsc->thread, "swdraw", LV_THREAD_PRIO_HIGH, render_thread_cb, + LV_DRAW_THREAD_STACK_SIZE, thread_dsc); } +#endif #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG tvg_engine_init(TVG_ENGINE_SW, 0); @@ -112,236 +118,26 @@ static int32_t lv_draw_sw_delete(lv_draw_unit_t * draw_unit) #if LV_USE_OS lv_draw_sw_unit_t * draw_sw_unit = (lv_draw_sw_unit_t *) draw_unit; - LV_LOG_INFO("cancel software rendering thread"); - draw_sw_unit->exit_status = true; + uint32_t i; + for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) { + lv_draw_sw_thread_dsc_t * thread_dsc = &draw_sw_unit->thread_dscs[i]; - if(draw_sw_unit->inited) { - lv_thread_sync_signal(&draw_sw_unit->sync); + LV_LOG_INFO("cancel software rendering thread"); + thread_dsc->exit_status = true; + + if(thread_dsc->inited) { + lv_thread_sync_signal(&thread_dsc->sync); + } + lv_thread_delete(&thread_dsc->thread); } - return lv_thread_delete(&draw_sw_unit->thread); + return 0; #else LV_UNUSED(draw_unit); return 0; #endif } -/********************** - * STATIC FUNCTIONS - **********************/ -static inline void execute_drawing_unit(lv_draw_sw_unit_t * u) -{ - execute_drawing(u); - - u->task_act->state = LV_DRAW_TASK_STATE_READY; - u->task_act = NULL; - - /*The draw unit is free now. Request a new dispatching as it can get a new task*/ - lv_draw_dispatch_request(); -} - -static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task) -{ - LV_UNUSED(draw_unit); - - switch(task->type) { - case LV_DRAW_TASK_TYPE_IMAGE: - case LV_DRAW_TASK_TYPE_LAYER: { - lv_draw_image_dsc_t * draw_dsc = task->draw_dsc; - - /* not support skew */ - if(draw_dsc->skew_x != 0 || draw_dsc->skew_y != 0) { - return 0; - } - - bool masked = draw_dsc->bitmap_mask_src != NULL; - - lv_color_format_t cf = draw_dsc->header.cf; - if(masked && (cf == LV_COLOR_FORMAT_A8 || cf == LV_COLOR_FORMAT_RGB565A8)) { - return 0; - } - - if(cf >= LV_COLOR_FORMAT_PROPRIETARY_START) { - return 0; - } - } - break; - default: - break; - } - - if(task->preference_score >= 100) { - task->preference_score = 100; - task->preferred_draw_unit_id = DRAW_UNIT_ID_SW; - } - - return 0; -} - -static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) -{ - LV_PROFILER_DRAW_BEGIN; - lv_draw_sw_unit_t * draw_sw_unit = (lv_draw_sw_unit_t *) draw_unit; - - /*Return immediately if it's busy with draw task*/ - if(draw_sw_unit->task_act) { - LV_PROFILER_DRAW_END; - return 0; - } - - lv_draw_task_t * t = NULL; - t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_SW); - if(t == NULL) { - LV_PROFILER_DRAW_END; - return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ - } - - void * buf = lv_draw_layer_alloc_buf(layer); - if(buf == NULL) { - LV_PROFILER_DRAW_END; - return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ - } - - t->state = LV_DRAW_TASK_STATE_IN_PROGRESS; - draw_sw_unit->task_act = t; - -#if LV_USE_OS - /*Let the render thread work*/ - if(draw_sw_unit->inited) lv_thread_sync_signal(&draw_sw_unit->sync); -#else - execute_drawing_unit(draw_sw_unit); -#endif - LV_PROFILER_DRAW_END; - return 1; -} - -#if LV_USE_OS -static void render_thread_cb(void * ptr) -{ - lv_draw_sw_unit_t * u = ptr; - - lv_thread_sync_init(&u->sync); - u->inited = true; - - while(1) { - while(u->task_act == NULL) { - if(u->exit_status) { - break; - } - lv_thread_sync_wait(&u->sync); - } - - if(u->exit_status) { - LV_LOG_INFO("ready to exit software rendering thread"); - break; - } - - execute_drawing_unit(u); - } - - u->inited = false; - lv_thread_sync_delete(&u->sync); - LV_LOG_INFO("exit software rendering thread"); -} -#endif - -static void execute_drawing(lv_draw_sw_unit_t * u) -{ - LV_PROFILER_DRAW_BEGIN; - /*Render the draw task*/ - lv_draw_task_t * t = u->task_act; -#if LV_USE_PARALLEL_DRAW_DEBUG - t->draw_unit = &u->base_unit; -#endif - switch(t->type) { - case LV_DRAW_TASK_TYPE_FILL: - lv_draw_sw_fill(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_BORDER: - lv_draw_sw_border(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_BOX_SHADOW: - lv_draw_sw_box_shadow(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_LETTER: - lv_draw_sw_letter(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_LABEL: - lv_draw_sw_label(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_IMAGE: - lv_draw_sw_image(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_ARC: - lv_draw_sw_arc(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_LINE: - lv_draw_sw_line(t, t->draw_dsc); - break; - case LV_DRAW_TASK_TYPE_TRIANGLE: - lv_draw_sw_triangle(t, t->draw_dsc); - break; - case LV_DRAW_TASK_TYPE_LAYER: - lv_draw_sw_layer(t, t->draw_dsc, &t->area); - break; - case LV_DRAW_TASK_TYPE_MASK_RECTANGLE: - lv_draw_sw_mask_rect(t, t->draw_dsc); - break; -#if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG - case LV_DRAW_TASK_TYPE_VECTOR: - lv_draw_sw_vector(t, t->draw_dsc); - break; -#endif - default: - break; - } - -#if LV_USE_PARALLEL_DRAW_DEBUG - /*Layers manage it for themselves*/ - if(t->type != LV_DRAW_TASK_TYPE_LAYER) { - lv_area_t draw_area; - if(!lv_area_intersect(&draw_area, &t->area, &t->clip_area)) return; - - int32_t idx = u->base_unit.idx; - - lv_draw_fill_dsc_t fill_dsc; - lv_draw_fill_dsc_init(&fill_dsc); - fill_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST); - fill_dsc.opa = LV_OPA_10; - lv_draw_sw_fill(t, &fill_dsc, &draw_area); - - lv_draw_border_dsc_t border_dsc; - lv_draw_border_dsc_init(&border_dsc); - border_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST); - border_dsc.opa = LV_OPA_60; - border_dsc.width = 1; - lv_draw_sw_border(t, &border_dsc, &draw_area); - - lv_point_t txt_size; - lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); - - lv_area_t txt_area; - txt_area.x1 = draw_area.x1; - txt_area.y1 = draw_area.y1; - txt_area.x2 = draw_area.x1 + txt_size.x - 1; - txt_area.y2 = draw_area.y1 + txt_size.y - 1; - - lv_draw_fill_dsc_init(&fill_dsc); - fill_dsc.color = lv_color_white(); - lv_draw_sw_fill(t, &fill_dsc, &txt_area); - - char buf[8]; - lv_snprintf(buf, sizeof(buf), "%d", idx); - lv_draw_label_dsc_t label_dsc; - lv_draw_label_dsc_init(&label_dsc); - label_dsc.color = lv_color_black(); - label_dsc.text = buf; - lv_draw_sw_label(t, &label_dsc, &txt_area); - } -#endif - LV_PROFILER_DRAW_END; -} - bool lv_draw_sw_register_blend_handler(lv_draw_sw_custom_blend_handler_t * handler) { lv_draw_sw_custom_blend_handler_t * existing_handler = NULL; @@ -395,4 +191,276 @@ lv_draw_sw_blend_handler_t lv_draw_sw_get_blend_handler(lv_color_format_t dest_c return NULL; } +/********************** + * STATIC FUNCTIONS + **********************/ + +static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task) +{ + LV_UNUSED(draw_unit); + + switch(task->type) { + case LV_DRAW_TASK_TYPE_IMAGE: + case LV_DRAW_TASK_TYPE_LAYER: { + lv_draw_image_dsc_t * draw_dsc = task->draw_dsc; + + /* not support skew */ + if(draw_dsc->skew_x != 0 || draw_dsc->skew_y != 0) { + return 0; + } + + bool masked = draw_dsc->bitmap_mask_src != NULL; + + lv_color_format_t cf = draw_dsc->header.cf; + if(masked && (cf == LV_COLOR_FORMAT_A8 || cf == LV_COLOR_FORMAT_RGB565A8)) { + return 0; + } + + if(cf >= LV_COLOR_FORMAT_PROPRIETARY_START) { + return 0; + } + } + break; + default: + break; + } + + if(task->preference_score >= 100) { + task->preference_score = 100; + task->preferred_draw_unit_id = DRAW_UNIT_ID_SW; + } + + return 0; +} + +static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) +{ + LV_PROFILER_DRAW_BEGIN; + lv_draw_sw_unit_t * draw_sw_unit = (lv_draw_sw_unit_t *) draw_unit; + +#if LV_USE_OS + uint32_t i; + uint32_t taken_cnt = 0; + /* All idle (couldn't take any tasks): return LV_DRAW_UNIT_IDLE; + * All busy: return 0; as 0 tasks were taken + * Otherwise return taken_cnt; + */ + + /*If at least one is busy, it's not all idle*/ + bool all_idle = true; + for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) { + if(draw_sw_unit->thread_dscs[i].task_act) { + all_idle = false; + break; + } + } + + lv_draw_task_t * t = NULL; + for(i = 0; i < LV_DRAW_SW_DRAW_UNIT_CNT; i++) { + lv_draw_sw_thread_dsc_t * thread_dsc = &draw_sw_unit->thread_dscs[i]; + + /*Do nothing if busy*/ + if(thread_dsc->task_act) continue; + + /*Find an available task. Start from the previously taken task.*/ + t = lv_draw_get_next_available_task(layer, t, DRAW_UNIT_ID_SW); + + /*If there is not available task don't try other threads as there won't be available + *tasks for then either*/ + if(t == NULL) { + LV_PROFILER_DRAW_END; + if(all_idle) return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ + else return taken_cnt; + } + + /*Allocate a buffer if not done yet.*/ + void * buf = lv_draw_layer_alloc_buf(layer); + /*Do not return is failed. The other thread might already have a buffer can do something. */ + if(buf == NULL) continue; + + /*Take the task*/ + all_idle = false; + taken_cnt++; + t->state = LV_DRAW_TASK_STATE_IN_PROGRESS; + thread_dsc->task_act = t; + + /*Let the render thread work*/ + if(thread_dsc->inited) lv_thread_sync_signal(&thread_dsc->sync); + } + + if(all_idle) return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ + else return taken_cnt; + +#else + /*Return immediately if it's busy with draw task*/ + if(draw_sw_unit->task_act) { + LV_PROFILER_DRAW_END; + return 0; + } + + lv_draw_task_t * t = NULL; + t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_SW); + if(t == NULL) { + LV_PROFILER_DRAW_END; + return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ + } + + void * buf = lv_draw_layer_alloc_buf(layer); + if(buf == NULL) { + LV_PROFILER_DRAW_END; + return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/ + } + + t->state = LV_DRAW_TASK_STATE_IN_PROGRESS; + draw_sw_unit->task_act = t; + + execute_drawing(t); + draw_sw_unit->task_act->state = LV_DRAW_TASK_STATE_READY; + draw_sw_unit->task_act = NULL; + + /*The draw unit is free now. Request a new dispatching as it can get a new task*/ + lv_draw_dispatch_request(); + + LV_PROFILER_DRAW_END; + return 1; +#endif + +} + +#if LV_USE_OS +static void render_thread_cb(void * ptr) +{ + lv_draw_sw_thread_dsc_t * thread_dsc = ptr; + + lv_thread_sync_init(&thread_dsc->sync); + thread_dsc->inited = true; + + while(1) { + while(thread_dsc->task_act == NULL) { + if(thread_dsc->exit_status) { + break; + } + lv_thread_sync_wait(&thread_dsc->sync); + } + + if(thread_dsc->exit_status) { + LV_LOG_INFO("ready to exit software rendering thread"); + break; + } + + execute_drawing(thread_dsc->task_act); +#if LV_USE_PARALLEL_DRAW_DEBUG + parallel_debug_draw(thread_dsc->task_act, thread_dsc->idx); +#endif + thread_dsc->task_act->state = LV_DRAW_TASK_STATE_READY; + thread_dsc->task_act = NULL; + + /*The draw unit is free now. Request a new dispatching as it can get a new task*/ + lv_draw_dispatch_request(); + + } + + thread_dsc->inited = false; + lv_thread_sync_delete(&thread_dsc->sync); + LV_LOG_INFO("exit software rendering thread"); +} +#endif + +static void execute_drawing(lv_draw_task_t * t) +{ + LV_PROFILER_DRAW_BEGIN; + /*Render the draw task*/ + switch(t->type) { + case LV_DRAW_TASK_TYPE_FILL: + lv_draw_sw_fill(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_BORDER: + lv_draw_sw_border(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_BOX_SHADOW: + lv_draw_sw_box_shadow(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_LETTER: + lv_draw_sw_letter(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_LABEL: + lv_draw_sw_label(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_IMAGE: + lv_draw_sw_image(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_ARC: + lv_draw_sw_arc(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_LINE: + lv_draw_sw_line(t, t->draw_dsc); + break; + case LV_DRAW_TASK_TYPE_TRIANGLE: + lv_draw_sw_triangle(t, t->draw_dsc); + break; + case LV_DRAW_TASK_TYPE_LAYER: + lv_draw_sw_layer(t, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_MASK_RECTANGLE: + lv_draw_sw_mask_rect(t, t->draw_dsc); + break; +#if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG + case LV_DRAW_TASK_TYPE_VECTOR: + lv_draw_sw_vector(t, t->draw_dsc); + break; +#endif + default: + break; + } + + + LV_PROFILER_DRAW_END; +} + +#if LV_USE_PARALLEL_DRAW_DEBUG +static void parallel_debug_draw(lv_draw_task_t * t, uint32_t idx) +{ + /*Layers manage it for themselves*/ + if(t->type != LV_DRAW_TASK_TYPE_LAYER) { + lv_area_t draw_area; + if(!lv_area_intersect(&draw_area, &t->area, &t->clip_area)) return; + + lv_draw_fill_dsc_t fill_dsc; + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST); + fill_dsc.opa = LV_OPA_10; + lv_draw_sw_fill(t, &fill_dsc, &draw_area); + + lv_draw_border_dsc_t border_dsc; + lv_draw_border_dsc_init(&border_dsc); + border_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST); + border_dsc.opa = LV_OPA_60; + border_dsc.width = 1; + lv_draw_sw_border(t, &border_dsc, &draw_area); + + lv_point_t txt_size; + lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); + + lv_area_t txt_area; + txt_area.x1 = draw_area.x1; + txt_area.y1 = draw_area.y1; + txt_area.x2 = draw_area.x1 + txt_size.x - 1; + txt_area.y2 = draw_area.y1 + txt_size.y - 1; + + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_color_white(); + lv_draw_sw_fill(t, &fill_dsc, &txt_area); + + char buf[8]; + lv_snprintf(buf, sizeof(buf), "%d", idx); + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + label_dsc.color = lv_color_black(); + label_dsc.text = buf; + lv_draw_sw_label(t, &label_dsc, &txt_area); + } +} +#endif + + #endif /*LV_USE_DRAW_SW*/ diff --git a/src/draw/sw/lv_draw_sw_private.h b/src/draw/sw/lv_draw_sw_private.h index 99ed9d7bb0..60bf4b6310 100644 --- a/src/draw/sw/lv_draw_sw_private.h +++ b/src/draw/sw/lv_draw_sw_private.h @@ -31,14 +31,22 @@ extern "C" { * TYPEDEFS **********************/ -struct _lv_draw_sw_unit_t { - lv_draw_unit_t base_unit; +typedef struct { lv_draw_task_t * task_act; -#if LV_USE_OS - lv_thread_sync_t sync; lv_thread_t thread; + lv_thread_sync_t sync; + lv_draw_unit_t * draw_unit; + uint32_t idx; volatile bool inited; volatile bool exit_status; +} lv_draw_sw_thread_dsc_t; + +struct _lv_draw_sw_unit_t { + lv_draw_unit_t base_unit; +#if LV_USE_OS + lv_draw_sw_thread_dsc_t thread_dscs[LV_DRAW_SW_DRAW_UNIT_CNT]; +#else + lv_draw_task_t * task_act; #endif }; diff --git a/src/draw/vg_lite/lv_draw_vg_lite.c b/src/draw/vg_lite/lv_draw_vg_lite.c index 02a5b0d93f..a154f9df15 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite.c +++ b/src/draw/vg_lite/lv_draw_vg_lite.c @@ -198,7 +198,7 @@ static int32_t draw_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) } /* Try to get an ready to draw. */ - lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, VG_LITE_DRAW_UNIT_ID); + lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, VG_LITE_DRAW_UNIT_ID); /* Return 0 is no selection, some tasks can be supported by other units. */ if(!t || t->preferred_draw_unit_id != VG_LITE_DRAW_UNIT_ID) { diff --git a/src/libs/thorvg/tvgArray.h b/src/libs/thorvg/tvgArray.h index e26dcf9490..4bcd9f64d3 100644 --- a/src/libs/thorvg/tvgArray.h +++ b/src/libs/thorvg/tvgArray.h @@ -30,6 +30,7 @@ #include #include #include +#include "tvgCommon.h" namespace tvg {