From d4cf52524ddb72d31f646be62067e77288a91844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ball=C3=B3=20Gy=C3=B6rgy?= Date: Thu, 5 Oct 2023 14:30:33 +0200 Subject: [PATCH] glamor: Fallback to software rendering on GLSL link failure Instead of thowing fatal error on GLSL link failure, fall back to software rendering. This allows using Glamor on systems with limited hardware resources (such as i915). (cherry picked from commit 007e98b18665ec76c48e0923f10431175755386f) Part-of: --- glamor/glamor.c | 43 ++++++++++------------------------------ glamor/glamor_core.c | 5 +++-- glamor/glamor_gradient.c | 36 +++++++++++++++++++++++---------- glamor/glamor_priv.h | 7 +++---- glamor/glamor_program.c | 3 ++- glamor/glamor_render.c | 39 +++++++++++++++++++++++++++++++----- 6 files changed, 77 insertions(+), 56 deletions(-) diff --git a/glamor/glamor.c b/glamor/glamor.c index 8b8590f73..b42345f8e 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -372,35 +372,6 @@ fallback: } -static Bool -glamor_check_instruction_count(int gl_version) -{ - GLint max_native_alu_instructions; - - /* Avoid using glamor if the reported instructions limit is too low, - * as this would cause glamor to fallback on sw due to large shaders - * which ends up being unbearably slow. - */ - if (gl_version < 30) { - if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) { - ErrorF("GL_ARB_fragment_program required\n"); - return FALSE; - } - - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, - GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, - &max_native_alu_instructions); - if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) { - LogMessage(X_WARNING, - "glamor requires at least %d instructions (%d reported)\n", - GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions); - return FALSE; - } - } - - return TRUE; -} - static void GLAPIENTRY glamor_debug_output_callback(GLenum source, GLenum type, @@ -759,9 +730,6 @@ glamor_init(ScreenPtr screen, unsigned int flags) goto fail; } - if (!glamor_check_instruction_count(gl_version)) - goto fail; - /* Glamor rendering assumes that platforms with GLSL 130+ * have instanced arrays, but this is not always the case. * etnaviv offers GLSL 140 with OpenGL 2.1. @@ -922,7 +890,16 @@ glamor_init(ScreenPtr screen, unsigned int flags) ps->Glyphs = glamor_composite_glyphs; glamor_init_vbo(screen); - glamor_init_gradient_shader(screen); + + glamor_priv->enable_gradient_shader = TRUE; + + if (!glamor_init_gradient_shader(screen)) { + LogMessage(X_WARNING, + "glamor%d: Cannot initialize gradient shader, falling back to software rendering for gradients\n", + screen->myNum); + glamor_priv->enable_gradient_shader = FALSE; + } + glamor_pixmap_init(screen); glamor_sync_init(screen); diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index cb315e2d1..9a7510da0 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -78,7 +78,7 @@ glamor_compile_glsl_prog(GLenum type, const char *source) return prog; } -void +Bool glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...) { GLint ok; @@ -106,8 +106,9 @@ glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...) glGetProgramInfoLog(prog, size, NULL, info); ErrorF("Failed to link: %s\n", info); - FatalError("GLSL link failure\n"); + return FALSE; } + return TRUE; } diff --git a/glamor/glamor_gradient.c b/glamor/glamor_gradient.c index 4c7ae4d77..ed136d095 100644 --- a/glamor/glamor_gradient.c +++ b/glamor/glamor_gradient.c @@ -177,7 +177,7 @@ _glamor_create_getcolor_fs_source(ScreenPtr screen, int stops_count, } } -static void +static Bool _glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, int dyn_gen) { @@ -316,7 +316,7 @@ _glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, if ((glamor_priv->radial_max_nstops >= stops_count) && (dyn_gen)) { /* Very Good, not to generate again. */ - return; + return TRUE; } glamor_make_current(glamor_priv); @@ -353,7 +353,10 @@ _glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position"); glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord"); - glamor_link_glsl_prog(screen, gradient_prog, "radial gradient"); + if (!glamor_link_glsl_prog(screen, gradient_prog, "radial gradient")) { + glDeleteProgram(gradient_prog); + return FALSE; + } if (dyn_gen) { index = 2; @@ -367,9 +370,11 @@ _glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, } glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][index] = gradient_prog; + + return TRUE; } -static void +static Bool _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int dyn_gen) { @@ -500,7 +505,7 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, if ((glamor_priv->linear_max_nstops >= stops_count) && (dyn_gen)) { /* Very Good, not to generate again. */ - return; + return TRUE; } glamor_make_current(glamor_priv); @@ -533,7 +538,10 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position"); glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord"); - glamor_link_glsl_prog(screen, gradient_prog, "linear gradient"); + if (!glamor_link_glsl_prog(screen, gradient_prog, "linear gradient")) { + glDeleteProgram(gradient_prog); + return FALSE; + } if (dyn_gen) { index = 2; @@ -547,9 +555,11 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, } glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][index] = gradient_prog; + + return TRUE; } -void +Bool glamor_init_gradient_shader(ScreenPtr screen) { glamor_screen_private *glamor_priv; @@ -564,11 +574,15 @@ glamor_init_gradient_shader(ScreenPtr screen) glamor_priv->linear_max_nstops = 0; glamor_priv->radial_max_nstops = 0; - _glamor_create_linear_gradient_program(screen, 0, 0); - _glamor_create_linear_gradient_program(screen, LINEAR_LARGE_STOPS, 0); + if (!_glamor_create_linear_gradient_program(screen, 0, 0) || + !_glamor_create_linear_gradient_program(screen, LINEAR_LARGE_STOPS, 0)) + return FALSE; - _glamor_create_radial_gradient_program(screen, 0, 0); - _glamor_create_radial_gradient_program(screen, RADIAL_LARGE_STOPS, 0); + if (!_glamor_create_radial_gradient_program(screen, 0, 0) || + !_glamor_create_radial_gradient_program(screen, RADIAL_LARGE_STOPS, 0)) + return FALSE; + + return TRUE; } static void diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 61df458cc..4c2f4691c 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -246,6 +246,7 @@ typedef struct glamor_screen_private { Bool can_copyplane; Bool use_gpu_shader4; int max_fbo_size; + Bool enable_gradient_shader; /** * Stores information about supported formats. Note, that this list contains all @@ -628,7 +629,7 @@ Bool glamor_get_drawable_location(const DrawablePtr drawable); void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap, int *x, int *y); GLint glamor_compile_glsl_prog(GLenum type, const char *source); -void glamor_link_glsl_prog(ScreenPtr screen, GLint prog, +Bool glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...) _X_ATTRIBUTE_PRINTF(3,4); void glamor_get_color_4f_from_pixel(PixmapPtr pixmap, unsigned long fg_pixel, GLfloat *color); @@ -684,7 +685,7 @@ void glamor_trapezoids(CARD8 op, int ntrap, xTrapezoid *traps); /* glamor_gradient.c */ -void glamor_init_gradient_shader(ScreenPtr screen); +Bool glamor_init_gradient_shader(ScreenPtr screen); PicturePtr glamor_generate_linear_gradient_picture(ScreenPtr screen, PicturePtr src_picture, int x_source, int y_source, @@ -961,6 +962,4 @@ void glamor_xv_render(glamor_port_private *port_priv, int id); #include "glamor_font.h" -#define GLAMOR_MIN_ALU_INSTRUCTIONS 128 /* Minimum required number of native ALU instructions */ - #endif /* GLAMOR_PRIV_H */ diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c index 1d9277eee..633cf6529 100644 --- a/glamor/glamor_program.c +++ b/glamor/glamor_program.c @@ -376,7 +376,8 @@ glamor_build_program(ScreenPtr screen, glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1"); } - glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name); + if (!glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name)) + goto fail; prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix"); prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg"); diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c index 43859ebde..a638d46ef 100644 --- a/glamor/glamor_render.c +++ b/glamor/glamor_render.c @@ -61,7 +61,7 @@ static struct blendinfo composite_op_info[] = { #define RepeatFix 10 static GLuint -glamor_create_composite_fs(glamor_screen_private *glamor_priv, struct shader_key *key) +glamor_create_composite_fs(glamor_screen_private *glamor_priv, struct shader_key *key, Bool enable_rel_sampler) { const char *repeat_define = "#define RepeatNone 0\n" @@ -131,6 +131,15 @@ glamor_create_composite_fs(glamor_screen_private *glamor_priv, struct shader_key " }\n" " return vec4(texture(tex_image, tex).rgb, 1.0);\n" "}\n"; + const char *stub_rel_sampler = + " vec4 rel_sampler_rgba(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n" + "{\n" + " return texture(tex_image, tex);\n" + "}\n" + " vec4 rel_sampler_rgbx(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n" + "{\n" + " return vec4(texture(tex_image, tex).rgb, 1.0);\n" + "}\n"; const char *source_solid_fetch = "uniform vec4 source;\n" @@ -319,7 +328,8 @@ glamor_create_composite_fs(glamor_screen_private *glamor_priv, struct shader_key GLAMOR_DEFAULT_PRECISION "%s%s%s%s%s%s%s%s", header, GLAMOR_COMPAT_DEFINES_FS, repeat_define, relocate_texture, - rel_sampler, source_fetch, mask_fetch, dest_swizzle, in); + enable_rel_sampler ? rel_sampler : stub_rel_sampler, + source_fetch, mask_fetch, dest_swizzle, in); prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source); free(source); @@ -383,18 +393,21 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key, GLuint vs, fs, prog; GLint source_sampler_uniform_location, mask_sampler_uniform_location; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + Bool enable_rel_sampler = TRUE; glamor_make_current(glamor_priv); vs = glamor_create_composite_vs(glamor_priv, key); if (vs == 0) return; - fs = glamor_create_composite_fs(glamor_priv, key); + fs = glamor_create_composite_fs(glamor_priv, key, enable_rel_sampler); if (fs == 0) return; prog = glCreateProgram(); glAttachShader(prog, vs); glAttachShader(prog, fs); + glDeleteShader(vs); + glDeleteShader(fs); glBindAttribLocation(prog, GLAMOR_VERTEX_POS, "v_position"); glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE, "v_texcoord0"); @@ -404,7 +417,22 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key, glBindFragDataLocationIndexed(prog, 0, 0, "color0"); glBindFragDataLocationIndexed(prog, 0, 1, "color1"); } - glamor_link_glsl_prog(screen, prog, "composite"); + + if (!glamor_link_glsl_prog(screen, prog, "composite")) { + /* Failed to link the shader, try again without rel_sampler. */ + enable_rel_sampler = FALSE; + glDetachShader(prog, fs); + fs = glamor_create_composite_fs(glamor_priv, key, enable_rel_sampler); + if (fs == 0) + return; + glAttachShader(prog, fs); + glDeleteShader(fs); + + if (!glamor_link_glsl_prog(screen, prog, "composite")) { + glDeleteProgram(prog); + return; + } + } shader->prog = prog; @@ -1369,6 +1397,7 @@ glamor_convert_gradient_picture(ScreenPtr screen, int error; PictFormatPtr pFormat; PictFormatShort format; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); if (source->pDrawable) { pFormat = source->pFormat; @@ -1378,7 +1407,7 @@ glamor_convert_gradient_picture(ScreenPtr screen, pFormat = PictureMatchFormat(screen, 32, format); } - if (!source->pDrawable) { + if (glamor_priv->enable_gradient_shader && !source->pDrawable) { if (source->pSourcePict->type == SourcePictTypeLinear) { dst = glamor_generate_linear_gradient_picture(screen, source, x_source,