mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-10 04:37:55 +08:00
fix(opengles): clear layer texture for transparent screen refresh (#9987)
Signed-off-by: Borgeuzz <mmam2407@gmail.com>
This commit is contained in:
+25
-3
@@ -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;
|
||||
|
||||
@@ -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
|
||||
**********************/
|
||||
|
||||
@@ -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
|
||||
**********************/
|
||||
|
||||
Reference in New Issue
Block a user