feat(draw_sw): have only one SW draw unit with multiple threads internally (#7899)

This commit is contained in:
Gabor Kiss-Vamosi
2025-03-11 14:18:27 +01:00
committed by GitHub
parent b4f256a40e
commit 90dcc889b2
14 changed files with 380 additions and 280 deletions
+1 -1
View File
@@ -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;
}
+43 -30
View File
@@ -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;
}
+13 -3
View File
@@ -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);
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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*/
#endif /*LV_USE_DRAW_G2D*/
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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) {
+1 -1
View File
@@ -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();
+300 -232
View File
File diff suppressed because it is too large Load Diff
+12 -4
View File
@@ -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
};
+1 -1
View File
@@ -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) {
+1
View File
@@ -30,6 +30,7 @@
#include <memory.h>
#include <cstdint>
#include <cstdlib>
#include "tvgCommon.h"
namespace tvg
{