feat(opengl): add matrix transformations to opengles rendering (#9654)

Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
VIFEX
2026-01-30 16:15:51 +08:00
committed by GitHub
parent 9a022e891e
commit 1f461786a7
7 changed files with 139 additions and 48 deletions

View File

@@ -2231,6 +2231,7 @@ menu "LVGL configuration"
config LV_USE_OPENGLES
bool "Use GLFW and OpenGL to open window on PC and handle mouse and keyboard"
depends on LV_USE_MATRIX
default n
config LV_USE_OPENGLES_DEBUG

View File

@@ -1408,7 +1408,9 @@
#define LV_UEFI_USE_MEMORY_SERVICES 0 /**< Use the memory functions from the boot services table */
#endif
/** Use a generic OpenGL driver that can be used to embed in other applications or used with GLFW/EGL */
/** Use a generic OpenGL driver that can be used to embed in other applications or used with GLFW/EGL
* - Requires LV_USE_MATRIX.
*/
#define LV_USE_OPENGLES 0
#if LV_USE_OPENGLES
#define LV_USE_OPENGLES_DEBUG 1 /**< Enable or disable debug for opengles */

View File

@@ -69,8 +69,22 @@ void lv_draw_nanovg_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc, const l
/* Use LVGL's OpenGL ES rendering infrastructure */
lv_opengles_viewport(0, 0, layer_w, layer_h);
lv_opengles_render_texture_rbswap(dsc->tex_id, &dest_area, dsc->opa, layer_w, layer_h,
&clip_area, dsc->h_flip, !dsc->v_flip);
lv_opengles_render_params_t params;
lv_opengles_render_params_init(&params);
params.texture = dsc->tex_id;
params.texture_area = &dest_area;
params.opa = dsc->opa;
params.disp_w = layer_w;
params.disp_h = layer_h;
params.texture_clip_area = &clip_area;
params.h_flip = dsc->h_flip;
params.v_flip = dsc->v_flip;
params.rb_swap = true;
#if LV_DRAW_TRANSFORM_USE_MATRIX
params.matrix = &layer->matrix;
#endif
lv_opengles_render(&params);
LV_PROFILER_DRAW_END;
}

View File

@@ -678,8 +678,18 @@ static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc
lv_area_t clip_area = t->clip_area;
lv_area_move(&clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
lv_opengles_render(dsc->tex_id, coords, dsc->opa, targ_tex_w, targ_tex_h, &clip_area, dsc->h_flip, !dsc->v_flip,
lv_color_black(), true, false);
lv_opengles_render_params_t params;
lv_opengles_render_params_init(&params);
params.texture = dsc->tex_id;
params.texture_area = coords;
params.opa = dsc->opa;
params.disp_w = targ_tex_w;
params.disp_h = targ_tex_h;
params.texture_clip_area = &clip_area;
params.h_flip = dsc->h_flip;
params.v_flip = !dsc->v_flip;
params.blend_opt = true;
lv_opengles_render(&params);
if(target_texture) {
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));

View File

@@ -12,6 +12,7 @@
#include "../../misc/lv_types.h"
#include "../../misc/lv_profiler.h"
#include "../../misc/lv_matrix.h"
#include "lv_opengles_debug.h"
#include "lv_opengles_private.h"
@@ -146,12 +147,27 @@ void lv_opengles_deinit(void)
is_init = false;
}
void lv_opengles_render_params_init(lv_opengles_render_params_t * params)
{
LV_ASSERT_NULL(params);
lv_memzero(params, sizeof(lv_opengles_render_params_t));
}
void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip)
{
LV_PROFILER_DRAW_BEGIN;
lv_opengles_render(texture, texture_area, opa, disp_w, disp_h, texture_clip_area, h_flip, v_flip,
lv_color_black(), false, false);
lv_opengles_render_params_t params;
lv_opengles_render_params_init(&params);
params.texture = texture;
params.texture_area = texture_area;
params.opa = opa;
params.disp_w = disp_w;
params.disp_h = disp_h;
params.texture_clip_area = texture_clip_area;
params.h_flip = h_flip;
params.v_flip = v_flip;
lv_opengles_render(&params);
LV_PROFILER_DRAW_END;
}
@@ -160,15 +176,34 @@ void lv_opengles_render_texture_rbswap(unsigned int texture, const lv_area_t * t
int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip)
{
LV_PROFILER_DRAW_BEGIN;
lv_opengles_render(texture, texture_area, opa, disp_w, disp_h, texture_clip_area, h_flip, v_flip,
lv_color_black(), false, true);
lv_opengles_render_params_t params;
lv_opengles_render_params_init(&params);
params.texture = texture;
params.texture_area = texture_area;
params.opa = opa;
params.disp_w = disp_w;
params.disp_h = disp_h;
params.texture_clip_area = texture_clip_area;
params.h_flip = h_flip;
params.v_flip = v_flip;
params.rb_swap = true;
lv_opengles_render(&params);
LV_PROFILER_DRAW_END;
}
void lv_opengles_render_fill(lv_color_t color, const lv_area_t * area, lv_opa_t opa, int32_t disp_w, int32_t disp_h)
{
LV_PROFILER_DRAW_BEGIN;
lv_opengles_render(0, area, opa, disp_w, disp_h, area, false, false, color, false, true);
lv_opengles_render_params_t params;
lv_opengles_render_params_init(&params);
params.texture_area = area;
params.opa = opa;
params.disp_w = disp_w;
params.disp_h = disp_h;
params.texture_clip_area = area;
params.fill_color = color;
params.rb_swap = true;
lv_opengles_render(&params);
LV_PROFILER_DRAW_END;
}
@@ -257,41 +292,44 @@ void lv_opengles_reinit_state(void)
LV_PROFILER_DRAW_END;
}
void lv_opengles_render(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area,
bool h_flip, bool v_flip, lv_color_t fill_color, bool blend_opt, bool swap_red_blue)
void lv_opengles_render(const lv_opengles_render_params_t * params)
{
LV_ASSERT_NULL(params);
LV_PROFILER_DRAW_BEGIN;
lv_area_t intersection;
if(!lv_area_intersect(&intersection, texture_area, texture_clip_area)) {
if(!lv_area_intersect(&intersection, params->texture_area, params->texture_clip_area)) {
LV_PROFILER_DRAW_END;
return;
}
GL_CALL(glActiveTexture(GL_TEXTURE0));
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
GL_CALL(glBindTexture(GL_TEXTURE_2D, params->texture));
float tex_w = (float)lv_area_get_width(&intersection);
float tex_h = (float)lv_area_get_height(&intersection);
float hor_scale = tex_w / (float)disp_w;
float ver_scale = tex_h / (float)disp_h;
float hor_translate = (float)intersection.x1 / (float)disp_w * 2.0f - (1.0f - hor_scale);
float ver_translate = -((float)intersection.y1 / (float)disp_h * 2.0f - (1.0f - ver_scale));
hor_scale = h_flip ? -hor_scale : hor_scale;
ver_scale = v_flip ? ver_scale : -ver_scale;
float hor_scale = tex_w / (float)params->disp_w;
float ver_scale = tex_h / (float)params->disp_h;
float hor_translate = (float)intersection.x1 / (float)params->disp_w * 2.0f - (1.0f - hor_scale);
float ver_translate = -((float)intersection.y1 / (float)params->disp_h * 2.0f - (1.0f - ver_scale));
hor_scale = params->h_flip ? -hor_scale : hor_scale;
ver_scale = params->v_flip ? ver_scale : -ver_scale;
if(texture != 0) {
float clip_x1 = h_flip ? lv_opengles_map_float(texture_clip_area->x2, texture_area->x2, texture_area->x1, 0.f, 1.f)
: lv_opengles_map_float(texture_clip_area->x1, texture_area->x1, texture_area->x2, 0.f, 1.f);
float clip_x2 = h_flip ? lv_opengles_map_float(texture_clip_area->x1, texture_area->x2, texture_area->x1, 0.f, 1.f)
: lv_opengles_map_float(texture_clip_area->x2, texture_area->x1, texture_area->x2, 0.f, 1.f);
float clip_y1 = v_flip ? lv_opengles_map_float(texture_clip_area->y2, texture_area->y2, texture_area->y1, 0.f, 1.f)
: lv_opengles_map_float(texture_clip_area->y1, texture_area->y1, texture_area->y2, 0.f, 1.f);
float clip_y2 = v_flip ? lv_opengles_map_float(texture_clip_area->y1, texture_area->y2, texture_area->y1, 0.f, 1.f)
: lv_opengles_map_float(texture_clip_area->y2, texture_area->y1, texture_area->y2, 0.f, 1.f);
if(params->texture != 0) {
float clip_x1 = params->h_flip ? lv_opengles_map_float(params->texture_clip_area->x2, params->texture_area->x2,
params->texture_area->x1, 0.f, 1.f)
: lv_opengles_map_float(params->texture_clip_area->x1, params->texture_area->x1, params->texture_area->x2, 0.f, 1.f);
float clip_x2 = params->h_flip ? lv_opengles_map_float(params->texture_clip_area->x1, params->texture_area->x2,
params->texture_area->x1, 0.f, 1.f)
: lv_opengles_map_float(params->texture_clip_area->x2, params->texture_area->x1, params->texture_area->x2, 0.f, 1.f);
float clip_y1 = params->v_flip ? lv_opengles_map_float(params->texture_clip_area->y2, params->texture_area->y2,
params->texture_area->y1, 0.f, 1.f)
: lv_opengles_map_float(params->texture_clip_area->y1, params->texture_area->y1, params->texture_area->y2, 0.f, 1.f);
float clip_y2 = params->v_flip ? lv_opengles_map_float(params->texture_clip_area->y1, params->texture_area->y2,
params->texture_area->y1, 0.f, 1.f)
: lv_opengles_map_float(params->texture_clip_area->y2, params->texture_area->y1, params->texture_area->y2, 0.f, 1.f);
float positions[LV_OPENGLES_VERTEX_BUFFER_LEN] = {
const float positions[LV_OPENGLES_VERTEX_BUFFER_LEN] = {
-1.f, 1.0f, clip_x1, clip_y2,
1.0f, 1.0f, clip_x2, clip_y2,
1.0f, -1.0f, clip_x2, clip_y1,
@@ -300,23 +338,27 @@ void lv_opengles_render(unsigned int texture, const lv_area_t * texture_area, lv
lv_opengles_vertex_buffer_init(positions, sizeof(positions));
}
const float transposed_matrix[9] = {
hor_scale, 0.0f, 0.0f,
0.0f, ver_scale, 0.0f,
hor_translate, ver_translate, 1.0f
};
lv_matrix_t matrix;
lv_matrix_identity(&matrix);
if(params->matrix) {
lv_matrix_multiply(&matrix, params->matrix);
}
else {
lv_matrix_translate(&matrix, hor_translate, ver_translate);
lv_matrix_scale(&matrix, hor_scale, ver_scale);
}
lv_opengles_shader_bind();
lv_opengles_enable_blending(blend_opt);
lv_opengles_enable_blending(params->blend_opt);
lv_opengles_shader_set_uniform1f("u_ColorDepth", LV_COLOR_DEPTH);
lv_opengles_shader_set_uniform1i("u_Texture", 0);
lv_opengles_shader_set_uniformmatrix3fv("u_VertexTransform", 1, transposed_matrix);
lv_opengles_shader_set_uniform1f("u_Opa", (float)opa / (float)LV_OPA_100);
lv_opengles_shader_set_uniform1i("u_IsFill", texture == 0);
lv_opengles_shader_set_uniform3f("u_FillColor", (float)fill_color.red / 255.0f, (float)fill_color.green / 255.0f,
(float)fill_color.blue / 255.0f);
lv_opengles_shader_set_uniform1i("u_SwapRB", swap_red_blue ? 1 : 0);
lv_opengles_shader_set_uniformmatrix3fv("u_VertexTransform", 1, (const float *)&matrix);
lv_opengles_shader_set_uniform1f("u_Opa", (float)params->opa / (float)LV_OPA_100);
lv_opengles_shader_set_uniform1i("u_IsFill", params->texture == 0);
lv_opengles_shader_set_uniform3f("u_FillColor", (float)params->fill_color.red / 255.0f,
(float)params->fill_color.green / 255.0f,
(float)params->fill_color.blue / 255.0f);
lv_opengles_shader_set_uniform1i("u_SwapRB", params->rb_swap ? 1 : 0);
lv_opengles_render_draw();
lv_opengles_disable_blending();

View File

@@ -21,6 +21,10 @@ extern "C" {
#include "../../misc/lv_area.h"
#include "../../misc/lv_color.h"
#if !LV_USE_MATRIX
#error "LV_USE_OPENGLES requires LV_USE_MATRIX"
#endif
#if LV_USE_EGL
#include "glad/include/glad/gles2.h"
#include "glad/include/glad/egl.h"
@@ -111,19 +115,35 @@ extern "C" {
**********************/
typedef struct {
unsigned int texture;
const lv_area_t * texture_area;
lv_opa_t opa;
int32_t disp_w;
int32_t disp_h;
const lv_area_t * texture_clip_area;
bool h_flip;
bool v_flip;
bool rb_swap;
lv_color_t fill_color;
bool blend_opt;
const lv_matrix_t * matrix;
} lv_opengles_render_params_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_opengles_render(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area,
bool h_flip, bool v_flip, lv_color_t fill_color, bool blend_opt, bool flipRB);
/**
* Initialize the render parameters with default values
* @param params pointer to an initialized `lv_opengles_render_params_t` struct
*/
void lv_opengles_render_params_init(lv_opengles_render_params_t * params);
/**
* Render the content of the window/framebuffer using OpenGL
* @param params pointer to an initialized `lv_opengles_render_params_t` struct
*/
void lv_opengles_render(const lv_opengles_render_params_t * params);
/**
* Render a texture using alternate blending mode, with red and blue channels flipped in the shader.

View File

@@ -4515,7 +4515,9 @@
#endif
#endif
/** Use a generic OpenGL driver that can be used to embed in other applications or used with GLFW/EGL */
/** Use a generic OpenGL driver that can be used to embed in other applications or used with GLFW/EGL
* - Requires LV_USE_MATRIX.
*/
#ifndef LV_USE_OPENGLES
#ifdef CONFIG_LV_USE_OPENGLES
#define LV_USE_OPENGLES CONFIG_LV_USE_OPENGLES