mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-22 07:02:05 +08:00
perf(opengles): avoid texture cache interaction for non-cacheable tasks (#9910)
This commit is contained in:
@@ -63,7 +63,9 @@ static void execute_drawing(lv_draw_opengles_unit_t * u);
|
||||
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 bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data);
|
||||
static unsigned int draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data);
|
||||
static void draw_texture_to_framebuffer(lv_draw_opengles_unit_t * u, unsigned int texture);
|
||||
static void draw_to_framebuffer(lv_draw_opengles_unit_t * u);
|
||||
|
||||
static unsigned int layer_get_texture(lv_layer_t * layer);
|
||||
static unsigned int get_framebuffer(lv_draw_opengles_unit_t * u);
|
||||
@@ -166,7 +168,7 @@ void lv_draw_opengles_clear_layer_area(lv_layer_t * layer, const lv_area_t * are
|
||||
static bool opengles_texture_cache_create_cb(cache_data_t * cached_data, void * user_data)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool ret = draw_to_texture((lv_draw_opengles_unit_t *)user_data, cached_data);
|
||||
bool ret = draw_to_texture((lv_draw_opengles_unit_t *)user_data, cached_data) != 0;
|
||||
LV_PROFILER_DRAW_END;
|
||||
return ret;
|
||||
}
|
||||
@@ -260,11 +262,6 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
{
|
||||
LV_UNUSED(draw_unit);
|
||||
|
||||
if(task->type == LV_DRAW_TASK_TYPE_IMAGE &&
|
||||
((lv_draw_image_dsc_t *)task->draw_dsc)->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*If not refreshing the display probably it's a canvas rendering
|
||||
*which his not supported in OpenGL as it's not a texture.*/
|
||||
if(lv_refr_get_disp_refreshing() == NULL) return 0;
|
||||
@@ -276,7 +273,7 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data)
|
||||
static unsigned int draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * task = u->task_act;
|
||||
@@ -314,9 +311,19 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
}
|
||||
|
||||
lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
|
||||
cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
|
||||
lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
|
||||
if(cache_data != NULL) {
|
||||
lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
|
||||
cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
|
||||
LV_ASSERT_MALLOC(cache_data->draw_dsc);
|
||||
if(cache_data->draw_dsc == NULL) {
|
||||
if(obj) {
|
||||
lv_obj_set_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, original_send_draw_task_event);
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
return 0;
|
||||
}
|
||||
lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
|
||||
}
|
||||
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
@@ -328,7 +335,6 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
rect_dsc.bg_grad = fill_dsc->grad;
|
||||
rect_dsc.radius = fill_dsc->radius;
|
||||
rect_dsc.bg_opa = fill_dsc->opa;
|
||||
|
||||
lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
|
||||
}
|
||||
break;
|
||||
@@ -395,13 +401,17 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
lv_memcpy(&image_dsc, task->draw_dsc, sizeof(image_dsc));
|
||||
image_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_image(&dest_layer, &image_dsc, &task->area);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*The malloced cache_data->draw_dsc will be freed automatically on failure
|
||||
*in opengles_texture_cache_free_cb*/
|
||||
LV_LOG_ERROR("OpenGLES draw unit does not support tasks of type %d", task->type);
|
||||
if(obj) {
|
||||
lv_obj_set_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, original_send_draw_task_event);
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(dest_layer.draw_task_head) {
|
||||
@@ -413,16 +423,18 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
|
||||
unsigned int texture = create_texture(texture_w, texture_h, u->render_draw_buf.data);
|
||||
|
||||
cache_data->w = texture_w;
|
||||
cache_data->h = texture_h;
|
||||
cache_data->texture = texture;
|
||||
if(cache_data != NULL) {
|
||||
cache_data->w = texture_w;
|
||||
cache_data->h = texture_h;
|
||||
cache_data->texture = texture;
|
||||
}
|
||||
|
||||
if(obj) {
|
||||
lv_obj_set_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, original_send_draw_task_event);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return true;
|
||||
return texture;
|
||||
}
|
||||
|
||||
static void blend_texture_layer(lv_draw_task_t * t)
|
||||
@@ -477,6 +489,53 @@ static void blend_texture_layer(lv_draw_task_t * t)
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static void draw_texture_to_framebuffer(lv_draw_opengles_unit_t * u, unsigned int texture)
|
||||
{
|
||||
lv_draw_task_t * t = u->task_act;
|
||||
|
||||
bool h_flip = false;
|
||||
bool v_flip = false;
|
||||
#if LV_USE_3DTEXTURE
|
||||
if(t->type == LV_DRAW_TASK_TYPE_3D) {
|
||||
lv_draw_3d_dsc_t * _3d_dsc = (lv_draw_3d_dsc_t *)t->draw_dsc;
|
||||
h_flip = _3d_dsc->h_flip;
|
||||
v_flip = _3d_dsc->v_flip;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_layer_t * dest_layer = t->target_layer;
|
||||
unsigned int target_texture = layer_get_texture(dest_layer);
|
||||
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
|
||||
|
||||
if(target_texture) {
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
}
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_area_move(&t->clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_area_t render_area = t->_real_area;
|
||||
lv_area_move(&render_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_opengles_render_texture(texture, &render_area, 0xff, targ_tex_w, targ_tex_h, &t->clip_area, h_flip, v_flip);
|
||||
|
||||
if(target_texture) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_to_framebuffer(lv_draw_opengles_unit_t * u)
|
||||
{
|
||||
unsigned int texture = draw_to_texture(u, NULL);
|
||||
if(texture == 0) {
|
||||
/*Texture creation failed; nothing to render to the framebuffer.*/
|
||||
return;
|
||||
}
|
||||
draw_texture_to_framebuffer(u, texture);
|
||||
GL_CALL(glDeleteTextures(1, &texture));
|
||||
}
|
||||
|
||||
static void draw_from_cached_texture(lv_draw_task_t * t)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
@@ -547,54 +606,10 @@ static void draw_from_cached_texture(lv_draw_task_t * t)
|
||||
|
||||
cache_data_t * data_cached = lv_cache_entry_get_data(entry_cached);
|
||||
unsigned int texture = data_cached->texture;
|
||||
|
||||
lv_layer_t * dest_layer = t->target_layer;
|
||||
|
||||
unsigned int target_texture = layer_get_texture(dest_layer);
|
||||
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
|
||||
|
||||
if(target_texture) {
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
}
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_area_move(&t->clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_area_t render_area = t->_real_area;
|
||||
lv_area_move(&render_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_opengles_render_texture(texture, &render_area, 0xff, targ_tex_w, targ_tex_h, &t->clip_area, h_flip, v_flip);
|
||||
|
||||
if(target_texture) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
draw_texture_to_framebuffer(u, texture);
|
||||
|
||||
lv_cache_release(u->texture_cache, entry_cached, u);
|
||||
|
||||
/*Do not cache modifiable images as they might change in the next frame
|
||||
*resulting in stale textures in the cache. */
|
||||
if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
|
||||
lv_draw_image_dsc_t * img_dsc = (lv_draw_image_dsc_t *)t->draw_dsc;
|
||||
if(img_dsc->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) {
|
||||
lv_cache_drop(u->texture_cache, &data_to_find, u);
|
||||
}
|
||||
}
|
||||
/*Do not cache non static (const) texts as the text's pointer can be freed/reallocated
|
||||
*at any time resulting in a wild pointer in the cached draw dsc. */
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LABEL) {
|
||||
lv_draw_label_dsc_t * label_dsc = t->draw_dsc;
|
||||
if(!label_dsc->text_static) {
|
||||
lv_cache_drop(u->texture_cache, &data_to_find, u);
|
||||
}
|
||||
}
|
||||
/*Do not cache lines rendered from points at dsc->points will be freed*/
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_LINE) {
|
||||
lv_draw_line_dsc_t * line_dsc = t->draw_dsc;
|
||||
if(line_dsc->points) {
|
||||
lv_cache_drop(u->texture_cache, &data_to_find, u);
|
||||
}
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
@@ -604,60 +619,92 @@ static void execute_drawing(lv_draw_opengles_unit_t * u)
|
||||
t->draw_unit = (lv_draw_unit_t *)u;
|
||||
|
||||
/* the shader-based fill is not working reliably with EGL. */
|
||||
if(t->type == LV_DRAW_TASK_TYPE_FILL) {
|
||||
lv_draw_fill_dsc_t * fill_dsc = t->draw_dsc;
|
||||
if(fill_dsc->radius == 0 && fill_dsc->grad.dir == LV_GRAD_DIR_NONE) {
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t fill_area = t->area;
|
||||
lv_area_intersect(&fill_area, &fill_area, &t->clip_area);
|
||||
lv_area_move(&fill_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * fill_dsc = t->draw_dsc;
|
||||
if(fill_dsc->radius == 0 && fill_dsc->grad.dir == LV_GRAD_DIR_NONE) {
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t fill_area = t->area;
|
||||
lv_area_intersect(&fill_area, &fill_area, &t->clip_area);
|
||||
lv_area_move(&fill_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
unsigned int target_texture = layer_get_texture(layer);
|
||||
int32_t targ_tex_w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&layer->buf_area);
|
||||
unsigned int target_texture = layer_get_texture(layer);
|
||||
int32_t targ_tex_w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&layer->buf_area);
|
||||
|
||||
if(target_texture) {
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
if(target_texture) {
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
}
|
||||
|
||||
if(fill_dsc->opa >= LV_OPA_MAX) {
|
||||
float tex_w = (float)lv_area_get_width(&fill_area);
|
||||
float tex_h = (float)lv_area_get_height(&fill_area);
|
||||
GL_CALL(glEnable(GL_SCISSOR_TEST));
|
||||
GL_CALL(glScissor(fill_area.x1, targ_tex_h - fill_area.y1 - tex_h, tex_w, tex_h));
|
||||
/* swap red and blue channels here as they will be swapped back during flushing*/
|
||||
GL_CALL(glClearColor((float)fill_dsc->color.blue / 255.0f, (float)fill_dsc->color.green / 255.0f,
|
||||
(float)fill_dsc->color.red / 255.0f, 1.0f));
|
||||
GL_CALL(glClearDepthf(1.0f));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
GL_CALL(glDisable(GL_SCISSOR_TEST));
|
||||
}
|
||||
else {
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_opengles_render_fill(fill_dsc->color, &fill_area, fill_dsc->opa, targ_tex_w, targ_tex_h);
|
||||
}
|
||||
|
||||
if(target_texture) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(fill_dsc->opa >= LV_OPA_MAX) {
|
||||
float tex_w = (float)lv_area_get_width(&fill_area);
|
||||
float tex_h = (float)lv_area_get_height(&fill_area);
|
||||
GL_CALL(glEnable(GL_SCISSOR_TEST));
|
||||
GL_CALL(glScissor(fill_area.x1, targ_tex_h - fill_area.y1 - tex_h, tex_w, tex_h));
|
||||
/* swap red and blue channels here as they will be swapped back during flushing*/
|
||||
GL_CALL(glClearColor((float)fill_dsc->color.blue / 255.0f, (float)fill_dsc->color.green / 255.0f,
|
||||
(float)fill_dsc->color.red / 255.0f, 1.0f));
|
||||
GL_CALL(glClearDepthf(1.0f));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
GL_CALL(glDisable(GL_SCISSOR_TEST));
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
/*Do not cache modifiable images as they might change in the next frame
|
||||
*resulting in stale textures in the cache. */
|
||||
lv_draw_image_dsc_t * img_dsc = (lv_draw_image_dsc_t *)t->draw_dsc;
|
||||
if(img_dsc->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) {
|
||||
draw_to_framebuffer(u);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_opengles_render_fill(fill_dsc->color, &fill_area, fill_dsc->opa, targ_tex_w, targ_tex_h);
|
||||
case LV_DRAW_TASK_TYPE_LABEL: {
|
||||
/*Do not cache non static (const) texts as the text's pointer can be freed/reallocated
|
||||
*at any time resulting in a wild pointer in the cached draw dsc. */
|
||||
lv_draw_label_dsc_t * label_dsc = t->draw_dsc;
|
||||
if(!label_dsc->text_static) {
|
||||
draw_to_framebuffer(u);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(target_texture) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
case LV_DRAW_TASK_TYPE_LINE: {
|
||||
/*Do not cache lines rendered from points at dsc->points will be freed*/
|
||||
lv_draw_line_dsc_t * line_dsc = t->draw_dsc;
|
||||
if(line_dsc->points) {
|
||||
draw_to_framebuffer(u);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_LAYER: {
|
||||
blend_texture_layer(t);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LAYER) {
|
||||
blend_texture_layer(t);
|
||||
return;
|
||||
}
|
||||
|
||||
#if LV_USE_3DTEXTURE
|
||||
if(t->type == LV_DRAW_TASK_TYPE_3D) {
|
||||
lv_draw_opengles_3d(t, t->draw_dsc, &t->area);
|
||||
return;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_3D: {
|
||||
lv_draw_opengles_3d(t, t->draw_dsc, &t->area);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
draw_from_cached_texture(t);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user