From be5c662bae83ec946a74b91a97f74bcdcc0c1f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Mon, 11 Nov 2024 12:44:21 +0100 Subject: [PATCH] gl-renderer: Add OpenGL ES 2 support to texture swizzles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fallback to shader based swizzling when OpenGL ES 3 isn't available. Signed-off-by: Loïc Molinari --- libweston/renderer-gl/fragment.glsl | 56 ++++++++++++++++++++++----- libweston/renderer-gl/gl-renderer.c | 14 ++++++- libweston/renderer-gl/gl-shaders.c | 60 ++++++++++++++++++++++++++--- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/libweston/renderer-gl/fragment.glsl b/libweston/renderer-gl/fragment.glsl index abcb427a4..026c0df9f 100644 --- a/libweston/renderer-gl/fragment.glsl +++ b/libweston/renderer-gl/fragment.glsl @@ -131,6 +131,9 @@ uniform sampler2D tex_wireframe; uniform float view_alpha; uniform vec4 unicolor; uniform vec4 tint; +uniform ivec4 swizzle_idx[3]; +uniform vec4 swizzle_mask[3]; +uniform vec4 swizzle_sub[3]; #define MAX_CURVE_PARAMS 10 #define MAX_CURVESET_PARAMS (MAX_CURVE_PARAMS * 3) @@ -151,6 +154,39 @@ uniform HIGHPRECISION vec2 color_mapping_lut_scale_offset; #endif uniform HIGHPRECISION mat3 color_mapping_matrix; +/* + * 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 + * used to index the swizzling uniforms, which must appropriately be set prior + * to draw call. + */ +vec4 +texture2D_swizzle(sampler2D sampler, int unit, vec2 coord) +{ +#if GLES_API_MAJOR_VERSION == 3 + return texture2D(sampler, coord); +#else + vec4 color = texture2D(sampler, coord); + + /* Swizzle components. */ + color = vec4(color[swizzle_idx[unit].x], + color[swizzle_idx[unit].y], + color[swizzle_idx[unit].z], + color[swizzle_idx[unit].w]); + + /* Substitute with 0 or 1. */ + return color * swizzle_mask[unit] + swizzle_sub[unit]; +#endif +} + +#if DEF_VARIANT == SHADER_VARIANT_EXTERNAL +vec4 +texture2D_swizzle(samplerExternalOES sampler, int unit, vec2 coord) +{ + return texture2D(sampler, coord); +} +#endif + vec4 sample_input_texture() { @@ -162,11 +198,11 @@ sample_input_texture() return unicolor; if (c_variant == SHADER_VARIANT_EXTERNAL) - return texture2D(tex, v_texcoord); + return texture2D_swizzle(tex, 0, v_texcoord); if (c_variant == SHADER_VARIANT_RGBA || c_variant == SHADER_VARIANT_RGBX) { - vec4 color = texture2D(tex, v_texcoord); + vec4 color = texture2D_swizzle(tex, 0, v_texcoord); if (c_variant == SHADER_VARIANT_RGBX) color.a = 1.0; @@ -177,20 +213,20 @@ sample_input_texture() /* Requires conversion to RGBA */ if (c_variant == SHADER_VARIANT_Y_U_V) { - yuva.x = texture2D(tex, v_texcoord).x; - yuva.y = texture2D(tex1, v_texcoord).x; - yuva.z = texture2D(tex2, v_texcoord).x; + yuva.x = texture2D_swizzle(tex, 0, v_texcoord).x; + yuva.y = texture2D_swizzle(tex1, 1, v_texcoord).x; + yuva.z = texture2D_swizzle(tex2, 2, v_texcoord).x; } else if (c_variant == SHADER_VARIANT_Y_UV) { - yuva.x = texture2D(tex, v_texcoord).x; - yuva.yz = texture2D(tex1, v_texcoord).rg; + yuva.x = texture2D_swizzle(tex, 0, v_texcoord).x; + yuva.yz = texture2D_swizzle(tex1, 1, v_texcoord).rg; } else if (c_variant == SHADER_VARIANT_Y_XUXV) { - yuva.x = texture2D(tex, v_texcoord).x; - yuva.yz = texture2D(tex1, v_texcoord).ga; + yuva.x = texture2D_swizzle(tex, 0, v_texcoord).x; + yuva.yz = texture2D_swizzle(tex1, 1, v_texcoord).ga; } else if (c_variant == SHADER_VARIANT_XYUV) { - yuva.xyz = texture2D(tex, v_texcoord).bgr; + yuva.xyz = texture2D_swizzle(tex, 0, v_texcoord).bgr; } else { /* Never reached, bad variant value. */ diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 31fb2fcd3..15fe4a0b2 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -2262,6 +2262,7 @@ blit_shadow_to_output(struct weston_output *output, pixman_region32_t *output_damage) { struct gl_output_state *go = get_output_state(output); + struct gl_renderer *gr = get_renderer(output->compositor); struct gl_shader_config sconf = { .req = { .variant = SHADER_VARIANT_RGBA, @@ -2282,7 +2283,6 @@ blit_shadow_to_output(struct weston_output *output, .input_param = &go->shadow_param, .input_num = 1, }; - struct gl_renderer *gr = get_renderer(output->compositor); double width = go->area.width; double height = go->area.height; struct weston_color_transform *ctransf; @@ -2805,14 +2805,24 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer) num_planes = yuv->output_planes; for (out = 0; out < num_planes; out++) { + const GLint swizzles_rg[] = { + GL_RED, GL_ALPHA, GL_ZERO, GL_ONE + }; const struct pixel_format_info *info; info = pixel_format_get_info(yuv->plane[out].format); assert(info); texture_format[out] = info->gl; - assert(yuv->plane[out].plane_index < (int) shm_plane_count); + /* Emulate red-green texture behaviour when + * gl_texture_2d_init() implicitly falls back to a + * luminance-alpha texture format. */ + if (!gl_features_has(gr, FEATURE_TEXTURE_RG) && + texture_format[out].internal == GL_RG8) + ARRAY_COPY(texture_format[out].swizzles.array, + swizzles_rg); + assert(yuv->plane[out].plane_index < (int) shm_plane_count); offset[out] = shm_offset[yuv->plane[out].plane_index]; } } else { diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 8a96e5719..d3275d780 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -60,6 +60,9 @@ struct gl_shader { GLint proj_uniform; GLint surface_to_buffer_uniform; GLint tex_uniforms[3]; + GLint swizzle_idx[3]; + GLint swizzle_mask[3]; + GLint swizzle_sub[3]; GLint tex_uniform_wireframe; GLint view_alpha_uniform; GLint color_uniform; @@ -282,7 +285,7 @@ gl_shader_create(struct gl_renderer *gr, { bool verbose = weston_log_scope_is_enabled(gr->shader_scope); struct gl_shader *shader = NULL; - char msg[512]; + char buffer[512]; GLint status; const char *sources[3]; char *conf = NULL; @@ -321,7 +324,12 @@ gl_shader_create(struct gl_renderer *gr, if (!conf) goto error_fragment; - sources[0] = "#version 100\n"; + sprintf(buffer, + "#version 100\n" + "#define GLES_API_MAJOR_VERSION %d\n", + gr->gl_version >= gl_version(3, 0) ? 3 : 2); + + sources[0] = buffer; sources[1] = conf; sources[2] = fragment_shader; shader->fragment_shader = compile_shader(GL_FRAGMENT_SHADER, @@ -346,8 +354,9 @@ gl_shader_create(struct gl_renderer *gr, glLinkProgram(shader->program); glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { - glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg); - weston_log("link info: %s\n", msg); + glGetProgramInfoLog(shader->program, sizeof buffer, NULL, + buffer); + weston_log("link info: %s\n", buffer); goto error_link; } @@ -363,6 +372,17 @@ gl_shader_create(struct gl_renderer *gr, if (requirements->wireframe) shader->tex_uniform_wireframe = glGetUniformLocation(shader->program, "tex_wireframe"); + if (gr->gl_version < gl_version(3, 0)) { + shader->swizzle_idx[0] = glGetUniformLocation(shader->program, "swizzle_idx[0]"); + shader->swizzle_idx[1] = glGetUniformLocation(shader->program, "swizzle_idx[1]"); + shader->swizzle_idx[2] = glGetUniformLocation(shader->program, "swizzle_idx[2]"); + shader->swizzle_mask[0] = glGetUniformLocation(shader->program, "swizzle_mask[0]"); + shader->swizzle_mask[1] = glGetUniformLocation(shader->program, "swizzle_mask[1]"); + shader->swizzle_mask[2] = glGetUniformLocation(shader->program, "swizzle_mask[2]"); + shader->swizzle_sub[0] = glGetUniformLocation(shader->program, "swizzle_sub[0]"); + shader->swizzle_sub[1] = glGetUniformLocation(shader->program, "swizzle_sub[1]"); + shader->swizzle_sub[2] = glGetUniformLocation(shader->program, "swizzle_sub[2]"); + } shader->view_alpha_uniform = glGetUniformLocation(shader->program, "view_alpha"); if (requirements->variant == SHADER_VARIANT_SOLID) { shader->color_uniform = glGetUniformLocation(shader->program, @@ -639,8 +659,12 @@ gl_shader_load_config(struct gl_renderer *gr, struct gl_shader *shader, const struct gl_shader_config *sconf) { + GLint *swizzles; + int swizzle_idx[4]; + float swizzle_mask[4]; + float swizzle_sub[4]; GLsizei n_params; - int i; + int i, j; glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, sconf->projection.d); @@ -659,6 +683,32 @@ gl_shader_load_config(struct gl_renderer *gr, assert(sconf->input_num <= SHADER_INPUT_TEX_MAX); for (i = 0; i < sconf->input_num; i++) { assert(shader->tex_uniforms[i] != -1); + + /* If the OpenGL ES implementation lacks swizzles as texture + * parameters (OpenGL ES 2), the fragment shader loads swizzling + * info from uniforms. */ + if (gr->gl_version < gl_version(3, 0)) { + swizzles = sconf->input_param[i].swizzles.array; + for (j = 0; j < 4; j++) { + swizzle_idx[j] = swizzles[j] - GL_RED; + if (swizzle_idx[j] >= 0) { + /* Swizzle is GL_RED, GL_GREEN, GL_BLUE + * or GL_ALPHA. */ + swizzle_mask[j] = 1.0f; + swizzle_sub[j] = 0.0f; + } else { + /* Swizzle is GL_ZERO (0) or GL_ONE + * (1). */ + swizzle_idx[j] = 0; + swizzle_mask[j] = 0.0f; + swizzle_sub[j] = (float) swizzles[j]; + } + } + glUniform4iv(shader->swizzle_idx[i], 1, swizzle_idx); + glUniform4fv(shader->swizzle_mask[i], 1, swizzle_mask); + glUniform4fv(shader->swizzle_sub[i], 1, swizzle_sub); + } + glUniform1i(shader->tex_uniforms[i], TEX_UNIT_IMAGES + i); glActiveTexture(GL_TEXTURE0 + TEX_UNIT_IMAGES + i); glBindTexture(sconf->input_param[i].target,