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 <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2025-10-13 15:44:06 +03:00
parent 27fd323478
commit a798e75257
4 changed files with 136 additions and 23 deletions

View file

@ -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,15 @@ 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;
uniform HIGHPRECISION mat3 color_cvd_simulation;
uniform HIGHPRECISION mat3 color_cvd_redistribution;
/*
* 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 +520,8 @@ wireframe()
return vec4(clamp(edge1 + edge2 + edge3, 0.0, 1.0));
}
void
main()
vec4
fragment_input_color_premult()
{
vec4 color;
@ -545,5 +560,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 */

View file

@ -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;

View file

@ -331,6 +331,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),
@ -5272,6 +5273,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);
@ -5414,6 +5419,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);
@ -5457,6 +5470,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;
}

View file

@ -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);
}