From aaed41798ffc98f70e62f31f409645d289934462 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 13 Oct 2025 15:44:06 +0300 Subject: [PATCH] renderer-gl: implement blend shader This prepares the fragment shader for blending in-shader instead of using the fixed-function blending. This is not yet used, but it will allow avoiding the 16F shadow framebuffer in the future. TEX_UNIT_LAST is actually a count rather than the index of the last unit. Fix the off-by-one in the check. The FB fetch/store curves push our potential texture count beyond 8, so implement a runtime check. Signed-off-by: Pekka Paalanen --- libweston/renderer-gl/fragment.glsl | 56 ++++++++++++++++++-- libweston/renderer-gl/gl-renderer-internal.h | 51 ++++++++++++------ libweston/renderer-gl/gl-renderer.c | 15 ++++++ libweston/renderer-gl/gl-shaders.c | 34 ++++++++++-- 4 files changed, 133 insertions(+), 23 deletions(-) diff --git a/libweston/renderer-gl/fragment.glsl b/libweston/renderer-gl/fragment.glsl index a0d8b90d0..c7b4f5f88 100644 --- a/libweston/renderer-gl/fragment.glsl +++ b/libweston/renderer-gl/fragment.glsl @@ -1,6 +1,6 @@ /* * Copyright 2012 Intel Corporation - * Copyright 2015,2019,2021 Collabora, Ltd. + * Copyright 2015,2019,2021-2025 Collabora, Ltd. * Copyright 2016 NVIDIA Corporation * Copyright 2021 Advanced Micro Devices, Inc. * @@ -68,6 +68,10 @@ #extension GL_OES_texture_3D : require #endif +#if DEF_SHADER_BLENDING +#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require +#endif + #ifdef GL_FRAGMENT_PRECISION_HIGH #define HIGHPRECISION highp #else @@ -84,6 +88,8 @@ compile_const int c_variant = DEF_VARIANT; compile_const int c_color_pre_curve = DEF_COLOR_PRE_CURVE; compile_const int c_color_mapping = DEF_COLOR_MAPPING; compile_const int c_color_post_curve = DEF_COLOR_POST_CURVE; +compile_const int c_fb_fetch_curve = DEF_FB_FETCH_CURVE; +compile_const int c_fb_store_curve = DEF_FB_STORE_CURVE; compile_const int c_color_effect = DEF_COLOR_EFFECT; compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT; @@ -160,6 +166,12 @@ uniform HIGHPRECISION vec3 color_mapping_offset; uniform HIGHPRECISION mat3 cvd_correction_matrix; +uniform lut_2d_t fb_fetch_curve_lut; +uniform parametric_curve_t fb_fetch_curve_par; + +uniform lut_2d_t fb_store_curve_lut; +uniform parametric_curve_t fb_store_curve_par; + /* * 2D texture sampler abstracting away the lack of swizzles on OpenGL ES 2. This * should only be used by code relying on swizzling. 'unit' is the texture unit @@ -505,8 +517,8 @@ wireframe() return vec4(clamp(edge1 + edge2 + edge3, 0.0, 1.0)); } -void -main() +vec4 +fragment_input_color_premult() { vec4 color; @@ -545,5 +557,41 @@ main() color = color * vec4(1.0 - src.a) + src; } - gl_FragColor = color; + return color; } + +#if DEF_SHADER_BLENDING + +layout(noncoherent) mediump vec4 gl_LastFragData[gl_MaxDrawBuffers]; + +void +main() +{ + vec4 src; + vec4 dst; + + src = fragment_input_color_premult(); + + /* Framebuffer must have straight alpha. */ + dst = gl_LastFragData[0]; + dst.rgb = color_curve(c_fb_fetch_curve, fb_fetch_curve_lut, + fb_fetch_curve_par, dst.rgb); + + /* glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); */ + dst = src + (1.0 - src.a) * dst; + + dst.rgb = color_curve(c_fb_store_curve, fb_store_curve_lut, + fb_store_curve_par, dst.rgb); + + gl_FragColor = dst; +} + +#else + +void +main() +{ + gl_FragColor = fragment_input_color_premult(); +} + +#endif /* DEF_SHADER_BLENDING */ diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index bc3845b3a..e55fc767c 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Collabora, Ltd. + * Copyright © 2019-2025 Collabora, Ltd. * Copyright © 2019 Harish Krupo * Copyright © 2019 Intel Corporation * Copyright 2021 Advanced Micro Devices, Inc. @@ -134,14 +134,15 @@ enum gl_extension_flag { EXTENSION_EXT_EGL_IMAGE_STORAGE = 1ull << 8, EXTENSION_EXT_MAP_BUFFER_RANGE = 1ull << 9, EXTENSION_EXT_READ_FORMAT_BGRA = 1ull << 10, - EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888 = 1ull << 11, - EXTENSION_EXT_TEXTURE_NORM16 = 1ull << 12, - EXTENSION_EXT_TEXTURE_RG = 1ull << 13, - EXTENSION_EXT_TEXTURE_SRGB_R8 = 1ull << 14, - EXTENSION_EXT_TEXTURE_SRGB_RG8 = 1ull << 15, - EXTENSION_EXT_TEXTURE_STORAGE = 1ull << 16, - EXTENSION_EXT_TEXTURE_TYPE_2_10_10_10_REV = 1ull << 17, - EXTENSION_EXT_UNPACK_SUBIMAGE = 1ull << 18, + EXTENSION_EXT_SHADER_FB_FETCH_NC = 1ull << 11, + EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888 = 1ull << 12, + EXTENSION_EXT_TEXTURE_NORM16 = 1ull << 13, + EXTENSION_EXT_TEXTURE_RG = 1ull << 14, + EXTENSION_EXT_TEXTURE_SRGB_R8 = 1ull << 15, + EXTENSION_EXT_TEXTURE_SRGB_RG8 = 1ull << 16, + EXTENSION_EXT_TEXTURE_STORAGE = 1ull << 17, + EXTENSION_EXT_TEXTURE_TYPE_2_10_10_10_REV = 1ull << 18, + EXTENSION_EXT_UNPACK_SUBIMAGE = 1ull << 19, EXTENSION_NV_PACKED_FLOAT = 1ull << 20, EXTENSION_NV_PIXEL_BUFFER_OBJECT = 1ull << 21, EXTENSION_OES_EGL_IMAGE = 1ull << 22, @@ -203,6 +204,10 @@ enum gl_feature_flag { /* GL renderer can create 3D textures. */ FEATURE_TEXTURE_3D = 1ull << 9, + + /* GL renderer can do blending explicitly in the fragment shader, + * using framebuffer fetch and store curves. */ + FEATURE_SHADER_BLENDING = 1ull << 10, }; /* Keep the following in sync with vertex.glsl. */ @@ -259,12 +264,16 @@ enum gl_tex_unit { TEX_UNIT_COLOR_MAPPING, TEX_UNIT_COLOR_POST_CURVE, TEX_UNIT_WIREFRAME, - TEX_UNIT_LAST, + + TEX_UNIT_COUNT_REQUIRED, + /* For all units below, check gr->max_texture_image_units etc. */ + + TEX_UNIT_FB_FETCH_CURVE = TEX_UNIT_COUNT_REQUIRED, + TEX_UNIT_FB_STORE_CURVE, + TEX_UNIT_COUNT_OPTIONAL, }; -static_assert(TEX_UNIT_LAST < 8, "OpenGL ES 2.0 requires at least 8 texture " - "units. Consider replacing this assert with a " - "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS check at display creation " - "to require more."); +static_assert(TEX_UNIT_COUNT_REQUIRED <= 8, "OpenGL ES 2.0 requires at least 8 texture " + "units. Cannot assume having more without a runtime check."); enum gl_bgra8_texture_support { BGRA8_TEXTURE_SUPPORT_STORAGE = 0, @@ -303,11 +312,15 @@ struct gl_shader_requirements unsigned color_mapping:2; /* enum gl_shader_color_mapping */ unsigned color_post_curve:3; /* enum gl_shader_color_curve */ + bool shader_blending:1; + unsigned fb_fetch_curve:3; /* enum gl_shader_color_curve */ + unsigned fb_store_curve:3; /* enum gl_shader_color_curve */ + /* * The total size of all bitfields plus pad_bits_ must fill up exactly * how many bytes the compiler allocates for them together. */ - unsigned pad_bits_:14; + unsigned pad_bits_:7; }; static_assert(sizeof(struct gl_shader_requirements) == 4 /* total bitfield size in bytes */, @@ -389,6 +402,9 @@ struct gl_shader_config { union gl_shader_config_color_mapping color_mapping; union gl_shader_config_color_curve color_post_curve; + union gl_shader_config_color_curve fb_fetch_curve; + union gl_shader_config_color_curve fb_store_curve; + enum weston_color_matrix_coef yuv_coefficients; enum weston_color_quant_range yuv_range; }; @@ -504,10 +520,15 @@ struct gl_renderer { PFNGLTEXSTORAGE2DEXTPROC tex_storage_2d; PFNGLTEXSTORAGE3DEXTPROC tex_storage_3d; + /* GL_EXT_shader_framebuffer_fetch_non_coherent */ + PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC framebuffer_fetch_barrier; + uint64_t features; GLenum pbo_usage; enum gl_bgra8_texture_support bgra8_texture_support; + int max_texture_image_units; + int max_combined_texture_image_units; bool blend_state; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 9715cc742..5d0497d84 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -339,6 +339,7 @@ static const struct gl_extension_table extension_table[] = { EXT("GL_EXT_EGL_image_storage", EXTENSION_EXT_EGL_IMAGE_STORAGE), EXT("GL_EXT_map_buffer_range", EXTENSION_EXT_MAP_BUFFER_RANGE), EXT("GL_EXT_read_format_bgra", EXTENSION_EXT_READ_FORMAT_BGRA), + EXT("GL_EXT_shader_framebuffer_fetch_non_coherent", EXTENSION_EXT_SHADER_FB_FETCH_NC), EXT("GL_EXT_texture_format_BGRA8888", EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888), EXT("GL_EXT_texture_norm16", EXTENSION_EXT_TEXTURE_NORM16), EXT("GL_EXT_texture_rg", EXTENSION_EXT_TEXTURE_RG), @@ -5452,6 +5453,10 @@ gl_renderer_setup(struct weston_compositor *ec) } gr->gl_version = get_gl_version(); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, + &gr->max_texture_image_units); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, + &gr->max_combined_texture_image_units); log_gl_info(gr); extensions = (const char *) glGetString(GL_EXTENSIONS); @@ -5594,6 +5599,14 @@ gl_renderer_setup(struct weston_compositor *ec) if (gl_has_sized_bgra8_renderbuffer(gr)) gr->features |= FEATURE_SIZED_BGRA8_RENDERBUFFER; + /* Shader blending feature. */ + if (gl_extensions_has(gr, EXTENSION_EXT_SHADER_FB_FETCH_NC) && + gr->max_texture_image_units >= TEX_UNIT_COUNT_OPTIONAL && + gr->max_combined_texture_image_units >= TEX_UNIT_COUNT_OPTIONAL) { + GET_PROC_ADDRESS(gr->framebuffer_fetch_barrier, "glFramebufferFetchBarrierEXT"); + gr->features |= FEATURE_SHADER_BLENDING; + } + gr->bgra8_texture_support = gl_get_bgra8_texture_support(gr); wl_list_init(&gr->pending_capture_list); @@ -5637,6 +5650,8 @@ gl_renderer_setup(struct weston_compositor *ec) weston_log_continue(STAMP_SPACE "Required precision: %s\n", yesno(gr->gl_version >= gl_version(3, 0) || gl_extensions_has(gr, EXTENSION_OES_REQUIRED_INTERNALFORMAT))); + weston_log_continue(STAMP_SPACE "In-shader blending: %s\n", + yesno(gl_features_has(gr, FEATURE_SHADER_BLENDING))); return 0; } diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 1eab6d89e..3eca63d42 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -1,6 +1,6 @@ /* * Copyright 2012 Intel Corporation - * Copyright 2015,2019,2021 Collabora, Ltd. + * Copyright 2015,2019,2021-2025 Collabora, Ltd. * Copyright 2016 NVIDIA Corporation * Copyright 2019 Harish Krupo * Copyright 2019 Intel Corporation @@ -95,6 +95,8 @@ struct gl_shader { union gl_shader_color_curve_uniforms color_pre_curve; union gl_shader_color_mapping_uniforms color_mapping; union gl_shader_color_curve_uniforms color_post_curve; + union gl_shader_color_curve_uniforms fb_fetch_curve; + union gl_shader_color_curve_uniforms fb_store_curve; GLint yuv_offsets_uniform; GLint yuv_coefficients_uniform; }; @@ -241,7 +243,7 @@ create_shader_description_string(const struct gl_shader_requirements *req) int size; char *str; - size = asprintf(&str, "%s %s %s %s %s %s %cinput_is_premult %ctint", + size = asprintf(&str, "%s %s %s %s %s %s %cinput_is_premult %ctint %cshader_blending (%s, %s)", gl_shader_texcoord_input_to_string(req->texcoord_input), gl_shader_texture_variant_to_string(req->variant), gl_shader_color_effect_to_string(req->color_effect), @@ -249,7 +251,10 @@ create_shader_description_string(const struct gl_shader_requirements *req) gl_shader_color_mapping_to_string(req->color_mapping), gl_shader_color_curve_to_string(req->color_post_curve), req->input_is_premult ? '+' : '-', - req->tint ? '+' : '-'); + req->tint ? '+' : '-', + req->shader_blending ? '+' : '-', + gl_shader_color_curve_to_string(req->fb_fetch_curve), + gl_shader_color_curve_to_string(req->fb_store_curve)); if (size < 0) return NULL; return str; @@ -286,6 +291,9 @@ create_fragment_shader_config_string(const struct gl_shader_requirements *req) "#define DEF_COLOR_PRE_CURVE %s\n" "#define DEF_COLOR_MAPPING %s\n" "#define DEF_COLOR_POST_CURVE %s\n" + "#define DEF_SHADER_BLENDING %s\n" + "#define DEF_FB_FETCH_CURVE %s\n" + "#define DEF_FB_STORE_CURVE %s\n" "#define DEF_COLOR_EFFECT %s\n" "#define DEF_VARIANT %s\n", ARRAY_LENGTH(((union weston_color_curve_parametric_chan_data){}).data), @@ -295,6 +303,9 @@ create_fragment_shader_config_string(const struct gl_shader_requirements *req) gl_shader_color_curve_to_string(req->color_pre_curve), gl_shader_color_mapping_to_string(req->color_mapping), gl_shader_color_curve_to_string(req->color_post_curve), + req->shader_blending ? "1" : "0", + gl_shader_color_curve_to_string(req->fb_fetch_curve), + gl_shader_color_curve_to_string(req->fb_store_curve), gl_shader_color_effect_to_string(req->color_effect), gl_shader_texture_variant_to_string(req->variant)); if (size < 0) @@ -505,8 +516,14 @@ gl_shader_create(struct gl_renderer *gr, shader->yuv_offsets_uniform = glGetUniformLocation(shader->program, "yuv_offsets"); - free(conf); + get_curve_uniform_locations(gr, &shader->fb_fetch_curve, + requirements->fb_fetch_curve, + shader->program, "fb_fetch_curve"); + get_curve_uniform_locations(gr, &shader->fb_store_curve, + requirements->fb_store_curve, + shader->program, "fb_store_curve"); + free(conf); wl_list_insert(&gr->shader_list, &shader->link); return shader; @@ -919,6 +936,15 @@ gl_shader_load_config(struct gl_renderer *gr, if (sconf->req.wireframe) glUniform1i(shader->tex_uniform_wireframe, TEX_UNIT_WIREFRAME); + if (sconf->req.shader_blending) { + gl_shader_load_config_curve(gr->compositor, sconf->req.fb_fetch_curve, + &sconf->fb_fetch_curve, &shader->fb_fetch_curve, + TEX_UNIT_FB_FETCH_CURVE); + gl_shader_load_config_curve(gr->compositor, sconf->req.fb_store_curve, + &sconf->fb_store_curve, &shader->fb_store_curve, + TEX_UNIT_FB_STORE_CURVE); + } + glActiveTexture(GL_TEXTURE0); }