From 2159fcb708bcbd938b297529f1015e069bac45f5 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 17 Dec 2025 15:16:34 -0500 Subject: [PATCH] feat(opengl): use only rgba format textures (#9304) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../embedded_linux/drivers/glfw.rst | 2 +- src/draw/opengles/lv_draw_opengles.c | 4 +-- src/drivers/display/drm/lv_linux_drm_egl.c | 2 +- .../opengles/assets/lv_opengles_shader.c | 8 ++++++ src/drivers/opengles/lv_opengles_driver.c | 25 ++++++++++++----- src/drivers/opengles/lv_opengles_driver.h | 2 +- src/drivers/opengles/lv_opengles_glfw.c | 17 ++++++------ src/drivers/opengles/lv_opengles_private.h | 27 ++++++++++++++++++- src/drivers/opengles/lv_opengles_texture.c | 4 +-- .../gltf_view/assets/lv_gltf_view_shader.c | 9 ++++--- .../gltf/gltf_view/lv_gltf_view_render.cpp | 6 +++-- 11 files changed, 78 insertions(+), 28 deletions(-) diff --git a/docs/src/integration/embedded_linux/drivers/glfw.rst b/docs/src/integration/embedded_linux/drivers/glfw.rst index 8a58e76af6..dbec7a9dae 100644 --- a/docs/src/integration/embedded_linux/drivers/glfw.rst +++ b/docs/src/integration/embedded_linux/drivers/glfw.rst @@ -181,7 +181,7 @@ used to add content to a texture and the driver will draw the texture in the win #else #error("Unsupported color format") #endif - glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data); + glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/src/draw/opengles/lv_draw_opengles.c b/src/draw/opengles/lv_draw_opengles.c index 1efe042613..444d396d7e 100644 --- a/src/draw/opengles/lv_draw_opengles.c +++ b/src/draw/opengles/lv_draw_opengles.c @@ -635,7 +635,7 @@ static unsigned int create_texture(int32_t w, int32_t h, const void * data) /* LV_COLOR_DEPTH 32, 16 are supported but the cached textures will always * have full ARGB pixels since the alpha channel is required for blending. */ - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)); #if 0 GL_CALL(glGenerateMipmap(GL_TEXTURE_2D)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 20)); @@ -677,7 +677,7 @@ static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc 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); + lv_color_black(), true, false); if(target_texture) { GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); diff --git a/src/drivers/display/drm/lv_linux_drm_egl.c b/src/drivers/display/drm/lv_linux_drm_egl.c index da80614e97..c669be2951 100644 --- a/src/drivers/display/drm/lv_linux_drm_egl.c +++ b/src/drivers/display/drm/lv_linux_drm_egl.c @@ -242,7 +242,7 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, disp_width, disp_height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, ctx->texture.fb1)); #elif LV_COLOR_DEPTH == 32 - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, disp_width, disp_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, disp_width, disp_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ctx->texture.fb1)); #else #error("Unsupported color format") diff --git a/src/drivers/opengles/assets/lv_opengles_shader.c b/src/drivers/opengles/assets/lv_opengles_shader.c index 04181bd4ad..ddc4a6f8b9 100644 --- a/src/drivers/opengles/assets/lv_opengles_shader.c +++ b/src/drivers/opengles/assets/lv_opengles_shader.c @@ -85,6 +85,7 @@ static const char *src_fragment_shader_v100 = R"( uniform float u_Opa; uniform bool u_IsFill; uniform vec3 u_FillColor; + uniform bool u_SwapRB; #ifdef HSV_ADJUST #include @@ -105,6 +106,9 @@ static const char *src_fragment_shader_v100 = R"( float combinedAlpha = texColor.a * u_Opa; gl_FragColor = vec4(texColor.rgb * combinedAlpha, combinedAlpha); } + if (u_SwapRB) { + gl_FragColor.bgr = gl_FragColor.rgb; + } #ifdef HSV_ADJUST gl_FragColor.rgb = adjustHSV(gl_FragColor.rgb); #endif @@ -208,6 +212,7 @@ static const char *src_fragment_shader_v300es = R"( uniform sampler2D u_Texture; uniform lowp float u_Opa; + uniform bool u_SwapRB; #ifdef HSV_ADJUST #include @@ -232,6 +237,9 @@ static const char *src_fragment_shader_v300es = R"( color.rgb *= color.a; } } + if (u_SwapRB) { + color.bgr = color.rgb; + } #ifdef HSV_ADJUST color.rgb = adjustHSV(color.rgb); #endif diff --git a/src/drivers/opengles/lv_opengles_driver.c b/src/drivers/opengles/lv_opengles_driver.c index 81669c264c..deb5078cab 100644 --- a/src/drivers/opengles/lv_opengles_driver.c +++ b/src/drivers/opengles/lv_opengles_driver.c @@ -86,8 +86,8 @@ static unsigned int index_buffer_count = 0; static unsigned int shader_id; -static const char * shader_names[] = { "u_Texture", "u_ColorDepth", "u_VertexTransform", "u_Opa", "u_IsFill", "u_FillColor", "u_Hue", "u_Saturation", "u_Value" }; -static int shader_location[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static const char * shader_names[] = { "u_Texture", "u_ColorDepth", "u_VertexTransform", "u_Opa", "u_IsFill", "u_FillColor", "u_SwapRB", "u_Hue", "u_Saturation", "u_Value" }; +static int shader_location[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /********************** * MACROS @@ -146,17 +146,26 @@ void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_ { 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); + lv_color_black(), false, false); + LV_PROFILER_DRAW_END; +} + +void lv_opengles_render_texture_rbswap(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, true); 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); + lv_opengles_render(0, area, opa, disp_w, disp_h, area, false, false, color, false, true); LV_PROFILER_DRAW_END; } - void lv_opengles_render_display_texture(lv_display_t * display, bool h_flip, bool v_flip) { LV_PROFILER_DRAW_BEGIN; @@ -190,6 +199,7 @@ void lv_opengles_render_display_texture(lv_display_t * display, bool h_flip, boo lv_opengles_shader_set_uniform1f("u_Opa", 1); lv_opengles_shader_set_uniform1i("u_IsFill", 0); lv_opengles_shader_set_uniform3f("u_FillColor", 1.0f, 1.0f, 1.0f); + lv_opengles_shader_set_uniform1i("u_SwapRB", 1); lv_opengles_render_draw(); LV_PROFILER_DRAW_END; @@ -211,7 +221,7 @@ void lv_opengles_viewport(int32_t x, int32_t y, int32_t w, int32_t h) 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 h_flip, bool v_flip, lv_color_t fill_color, bool blend_opt, bool swap_red_blue) { LV_PROFILER_DRAW_BEGIN; lv_area_t intersection; @@ -258,6 +268,7 @@ void lv_opengles_render(unsigned int texture, const lv_area_t * texture_area, lv hor_translate, ver_translate, 1.0f }; + lv_opengles_shader_bind(); lv_opengles_enable_blending(blend_opt); lv_opengles_shader_set_uniform1f("u_ColorDepth", LV_COLOR_DEPTH); @@ -267,6 +278,8 @@ void lv_opengles_render(unsigned int texture, const lv_area_t * texture_area, lv 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_render_draw(); lv_opengles_disable_blending(); LV_PROFILER_DRAW_END; diff --git a/src/drivers/opengles/lv_opengles_driver.h b/src/drivers/opengles/lv_opengles_driver.h index de075cc5f0..4034d978e6 100644 --- a/src/drivers/opengles/lv_opengles_driver.h +++ b/src/drivers/opengles/lv_opengles_driver.h @@ -58,7 +58,7 @@ void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_ int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip); /** - * Render a display texture - Supports rotation + * Render a display texture - Supports rotation - Switches red and blue channels * @param display LVGL Texture display. Created with the `lv_opengles_texture` module * @param h_flip horizontal flip * @param v_flip vertical flip diff --git a/src/drivers/opengles/lv_opengles_glfw.c b/src/drivers/opengles/lv_opengles_glfw.c index 1c5825a861..6cbbe9313c 100644 --- a/src/drivers/opengles/lv_opengles_glfw.c +++ b/src/drivers/opengles/lv_opengles_glfw.c @@ -518,10 +518,10 @@ static void window_update_handler(lv_timer_t * t) texture->fb)); #elif LV_COLOR_DEPTH == 24 GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lv_area_get_width(&texture->area), lv_area_get_height(&texture->area), 0, - GL_BGR, GL_UNSIGNED_BYTE, texture->fb)); + GL_RGB, GL_UNSIGNED_BYTE, texture->fb)); #elif LV_COLOR_DEPTH == 32 GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lv_area_get_width(&texture->area), lv_area_get_height(&texture->area), - 0, GL_BGRA, GL_UNSIGNED_BYTE, texture->fb)); + 0, GL_RGBA, GL_UNSIGNED_BYTE, texture->fb)); #else #error("Unsupported color format") #endif @@ -530,8 +530,9 @@ static void window_update_handler(lv_timer_t * t) GL_CALL(glBindTexture(GL_TEXTURE_2D, 0)); - lv_opengles_render_texture(window_display_texture, &texture->area, texture->opa, window->hor_res, window->ver_res, - &texture->area, window->h_flip, window->v_flip); + lv_opengles_render_texture_rbswap(window_display_texture, &texture->area, texture->opa, window->hor_res, + window->ver_res, + &texture->area, window->h_flip, window->v_flip); #endif } else { @@ -548,11 +549,11 @@ static void window_update_handler(lv_timer_t * t) } #if LV_USE_DRAW_OPENGLES - lv_opengles_render_texture(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res, - &texture->area, window->h_flip, texture->disp == NULL ? window->v_flip : !window->v_flip); + lv_opengles_render_texture_rbswap(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res, + &texture->area, window->h_flip, texture->disp == NULL ? window->v_flip : !window->v_flip); #else - lv_opengles_render_texture(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res, - &texture->area, window->h_flip, window->v_flip); + lv_opengles_render_texture_rbswap(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res, + &texture->area, window->h_flip, window->v_flip); #endif } } diff --git a/src/drivers/opengles/lv_opengles_private.h b/src/drivers/opengles/lv_opengles_private.h index e81e839da7..868697d2e3 100644 --- a/src/drivers/opengles/lv_opengles_private.h +++ b/src/drivers/opengles/lv_opengles_private.h @@ -105,7 +105,32 @@ extern "C" { 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 h_flip, bool v_flip, lv_color_t fill_color, bool blend_opt, bool flipRB); + + +/** + * Render a texture using alternate blending mode, with red and blue channels flipped in the shader. + * @param texture OpenGL texture ID + * @param texture_area the area in the window to render the texture in + * @param opa opacity to blend the texture with existing contents + * @param disp_w width of the window/framebuffer being rendered to + * @param disp_h height of the window/framebuffer being rendered to + * @param h_flip horizontal flip + * @param v_flip vertical flip + */ +void lv_opengles_render_texture_rbswap(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); + +/** + * Set the OpenGL viewport, with vertical co-ordinate conversion + * @param x x position of the viewport + * @param y y position of the viewport + * @param w width of the viewport + * @param h height of the viewport + */ +void lv_opengles_regular_viewport(int32_t x, int32_t y, int32_t w, int32_t h); + /********************** * MACROS diff --git a/src/drivers/opengles/lv_opengles_texture.c b/src/drivers/opengles/lv_opengles_texture.c index 71320d55b1..7406b84e03 100644 --- a/src/drivers/opengles/lv_opengles_texture.c +++ b/src/drivers/opengles/lv_opengles_texture.c @@ -208,7 +208,7 @@ static unsigned int create_texture(int32_t w, int32_t h) GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL)); #elif LV_COLOR_DEPTH == 32 - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)); #else #error("Unsupported color format") #endif @@ -251,7 +251,7 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, disp->hor_res, disp->ver_res, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, dsc->fb1)); #elif LV_COLOR_DEPTH == 32 - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, disp->hor_res, disp->ver_res, 0, GL_BGRA, GL_UNSIGNED_BYTE, dsc->fb1)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, disp->hor_res, disp->ver_res, 0, GL_RGBA, GL_UNSIGNED_BYTE, dsc->fb1)); #else #error("Unsupported color format") #endif diff --git a/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c b/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c index f4bb54fcf9..49e5555ef7 100644 --- a/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c +++ b/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c @@ -1098,7 +1098,7 @@ static const lv_opengl_shader_t src_includes[] = { vec3 getTransmissionSample(vec2 fragCoord, float roughness, float ior) { float framebufferLod = log2(float(u_TransmissionFramebufferSize.x)) * applyIorToRoughness(roughness, ior); - vec3 transmittedLight = textureLod(u_TransmissionFramebufferSampler, fragCoord.xy, framebufferLod).rgb; + vec3 transmittedLight = textureLod(u_TransmissionFramebufferSampler, fragCoord.xy, framebufferLod).bgr; // r/b switched intentionally; return transmittedLight; } @@ -2553,13 +2553,14 @@ static const lv_opengl_shader_t src_includes[] = { baseColor.a = 1.0; #endif + // The red and blue channels are switched after any tonemapping + // They will be switched back the correct way by the 2D shader #ifdef LINEAR_OUTPUT - g_finalColor = vec4(color.rgb, baseColor.a); + g_finalColor = vec4(color.bgr, baseColor.a); #else - g_finalColor = vec4(toneMap(color), baseColor.a); + g_finalColor = vec4(toneMap(color).bgr, baseColor.a); #endif - /* #else // In case of missing data for a debug view, render a checkerboard. diff --git a/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp b/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp index c927d7f857..062818460c 100644 --- a/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp +++ b/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp @@ -1207,8 +1207,10 @@ static void setup_draw_environment_background(lv_opengl_shader_manager_t * manag static void setup_draw_solid_background(lv_gltf_t * viewer, lv_color_t bg_color, lv_opa_t bg_opa) { GL_CALL(glClearDepthf(1.0f)); - GL_CALL(glClearColor((float)bg_color.red / 255.0f, (float)bg_color.green / 255.0f, - (float)bg_color.blue / 255.0f, (float)bg_opa / 255.0f)); + /* Red / blue color order reversed below so they'll end up in the correct order + * after the shader swaps the channels again, back to correct. */ + GL_CALL(glClearColor((float)bg_color.blue / 255.0f, (float)bg_color.green / 255.0f, + (float)bg_color.red / 255.0f, (float)bg_opa / 255.0f)); GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));