diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index 7c2f1ced82..6876edbe7e 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -21,6 +21,7 @@ #include "../misc/lv_profiler.h" #include "../misc/lv_types.h" #include "../draw/lv_draw_private.h" +#include "../draw/opengles/lv_draw_opengles.h" #include "../stdlib/lv_string.h" #include "lv_global.h" @@ -1057,9 +1058,30 @@ static void refr_configured_layer(lv_layer_t * layer) } /*If the screen is transparent initialize it when the flushing is ready*/ if(lv_color_format_has_alpha(disp_refr->color_format)) { - lv_area_t clear_area = layer->_clip_area; - lv_area_move(&clear_area, -layer->buf_area.x1, -layer->buf_area.y1); - lv_draw_buf_clear(layer->draw_buf, &clear_area); +#if LV_USE_DRAW_OPENGLES + lv_layer_t * clear_target_layer = disp_refr->layer_head ? disp_refr->layer_head : layer; + /* TODO: this driver-specific branch is a temporary workaround. + * The proper fix may be a generic per-draw-unit clear callback (e.g. + * a `clear_area_cb` on `lv_draw_unit_t`) so `lv_refr` can just dispatch + * the right clear function. LVGL does not currently expose that hook now. + * This is a special-case for Draw_OpenGLES to fix issue #9912 (PR #9987). + */ + /*With Draw_OpenGLES the layer's draw_buf is a dummy CPU buffer and the + *real pixels live in a GL texture. Clearing the CPU buffer is a no-op + *on the texture, so perform a GPU-side clear of the dirty area. + *Key this off the refreshing display's real backing layer instead of + *the current layer, because tiled rendering can use temporary tile + *layers with NULL user_data.*/ + if(disp_refr->layer_head != NULL && disp_refr->layer_head->user_data != NULL) { + lv_draw_opengles_clear_layer_area(clear_target_layer, &layer->_clip_area); + } + else +#endif + { + lv_area_t clear_area = layer->_clip_area; + lv_area_move(&clear_area, -layer->buf_area.x1, -layer->buf_area.y1); + lv_draw_buf_clear(layer->draw_buf, &clear_area); + } } lv_obj_t * top_act_scr = NULL; diff --git a/src/draw/opengles/lv_draw_opengles.c b/src/draw/opengles/lv_draw_opengles.c index edadb79e87..d669762219 100644 --- a/src/draw/opengles/lv_draw_opengles.c +++ b/src/draw/opengles/lv_draw_opengles.c @@ -128,6 +128,48 @@ void lv_draw_opengles_deinit(void) g_unit = NULL; } +void lv_draw_opengles_clear_layer_area(lv_layer_t * layer, const lv_area_t * area) +{ + if(g_unit == NULL) return; + unsigned int target_texture = layer_get_texture(layer); + if(target_texture == 0) return; + + lv_area_t a; + if(!lv_area_intersect(&a, area, &layer->_clip_area)) return; + lv_area_move(&a, -layer->buf_area.x1, -layer->buf_area.y1); + + int32_t w = lv_area_get_width(&a); + int32_t h = lv_area_get_height(&a); + if(w <= 0 || h <= 0) return; + + int32_t tex_h = lv_area_get_height(&layer->buf_area); + + GLint prev_fbo = 0; + GLint prev_scissor_box[4] = {0}; + GLfloat prev_clear_color[4] = {0}; + GLboolean prev_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + GL_CALL(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo)); + GL_CALL(glGetIntegerv(GL_SCISSOR_BOX, prev_scissor_box)); + GL_CALL(glGetFloatv(GL_COLOR_CLEAR_VALUE, prev_clear_color)); + + unsigned int framebuffer = get_framebuffer(g_unit); + GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); + GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0)); + + GL_CALL(glEnable(GL_SCISSOR_TEST)); + GL_CALL(glScissor(a.x1, tex_h - a.y1 - h, w, h)); + GL_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); + GL_CALL(glClear(GL_COLOR_BUFFER_BIT)); + + /*Restore previous GL state.*/ + if(!prev_scissor_test) { + GL_CALL(glDisable(GL_SCISSOR_TEST)); + } + GL_CALL(glScissor(prev_scissor_box[0], prev_scissor_box[1], prev_scissor_box[2], prev_scissor_box[3])); + GL_CALL(glClearColor(prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3])); + GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)prev_fbo)); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/draw/opengles/lv_draw_opengles.h b/src/draw/opengles/lv_draw_opengles.h index 1285c93ec6..3c72a99670 100644 --- a/src/draw/opengles/lv_draw_opengles.h +++ b/src/draw/opengles/lv_draw_opengles.h @@ -17,6 +17,9 @@ extern "C" { #include "../../lv_conf_internal.h" #if LV_USE_DRAW_OPENGLES +#include "../lv_draw.h" +#include "../../misc/lv_area.h" + /********************* * DEFINES *********************/ @@ -32,6 +35,18 @@ extern "C" { void lv_draw_opengles_init(void); void lv_draw_opengles_deinit(void); +/** + * Clear a region of the GPU texture that backs the given layer. + * Needed because `lv_draw_buf_clear` operates on the CPU draw buffer, + * which is only a dummy placeholder when the layer is rendered to a + * GL texture. Without this, a transparent screen background leaves + * stale pixels on the texture between frames. + * + * @param layer layer whose backing texture must be cleared + * @param area area (in layer/screen coordinates) to clear + */ +void lv_draw_opengles_clear_layer_area(lv_layer_t * layer, const lv_area_t * area); + /********************** * MACROS **********************/