gl-renderer: add fallback shader

If shader compiling on demand fails, then rather than using whatever
random shader happens to be current, use an explicit fallback shader
painting stuff brown.

The color is chosen dim enough to hopefully not cause problems even in
a HDR setting as it will be written verbatim into the fb/shadow.

This also prevents NULL dereference on shader->key.variant in
draw_view().

One way to test this shader is to hack fragment.glsl:
 #if DEF_VARIANT == SHADER_VARIANT_EXTERNAL
 #extension GL_OES_EGL_image_external : require
+#error haa haa
 #endif

and then run e.g. weston-simple-dmabuf-v4l -f YUYV
with vivid kernel module loaded. This worked on Intel.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 4 years ago
parent 06c9d0f054
commit c12963f98d
  1. 1
      libweston/renderer-gl/gl-renderer-internal.h
  2. 82
      libweston/renderer-gl/gl-renderer.c

@ -136,6 +136,7 @@ struct gl_renderer {
bool has_gl_texture_rg; bool has_gl_texture_rg;
struct gl_shader *current_shader; struct gl_shader *current_shader;
struct gl_shader *fallback_shader;
struct wl_signal destroy_signal; struct wl_signal destroy_signal;

@ -654,11 +654,42 @@ gl_renderer_get_program(struct gl_renderer *gr,
return NULL; return NULL;
} }
static struct gl_shader *
gl_renderer_create_fallback_shader(struct gl_renderer *gr)
{
static const struct gl_shader_requirements fallback_requirements = {
.variant = SHADER_VARIANT_SOLID,
};
struct gl_shader *shader;
shader = gl_shader_create(gr, &fallback_requirements);
if (!shader)
return NULL;
/*
* This shader must be exempt from any automatic garbage collection.
* It is destroyed explicitly.
*/
wl_list_remove(&shader->link);
wl_list_init(&shader->link);
return shader;
}
static bool static bool
gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader *shader) gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader **shaderp)
{ {
static const GLfloat fallback_shader_color[4] = { 0.2, 0.1, 0.0, 1.0 };
struct gl_shader *shader = *shaderp;
if (!shader) { if (!shader) {
weston_log("Error: trying to use NULL GL shader.\n"); weston_log("Error: trying to use NULL GL shader.\n");
gr->current_shader = NULL;
shader = gr->fallback_shader;
glUseProgram(shader->program);
glUniform4fv(shader->color_uniform, 1, fallback_shader_color);
glUniform1f(shader->alpha_uniform, 1.0f);
*shaderp = shader;
return false; return false;
} }
@ -694,7 +725,7 @@ triangle_fan_debug(struct weston_view *view, int first, int count)
}; };
shader = gl_renderer_get_program(gr, &requirements_triangle_fan); shader = gl_renderer_get_program(gr, &requirements_triangle_fan);
if (!gl_renderer_use_program(gr, shader)) if (!gl_renderer_use_program(gr, &shader))
return; return;
nelems = (count - 1 + count - 2) * 2; nelems = (count - 1 + count - 2) * 2;
@ -716,7 +747,7 @@ triangle_fan_debug(struct weston_view *view, int first, int count)
color[color_idx++ % ARRAY_LENGTH(color)]); color[color_idx++ % ARRAY_LENGTH(color)]);
glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer); glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
gl_renderer_use_program(gr, prev_shader); gl_renderer_use_program(gr, &prev_shader);
free(buffer); free(buffer);
} }
@ -803,26 +834,30 @@ gl_renderer_send_shader_error(struct weston_view *view)
static void static void
gl_renderer_use_program_with_view_uniforms(struct gl_renderer *gr, gl_renderer_use_program_with_view_uniforms(struct gl_renderer *gr,
struct gl_shader *shader, struct gl_shader **shaderp,
struct weston_view *view, struct weston_view *view,
struct weston_output *output) struct weston_output *output)
{ {
int i; int i;
struct gl_surface_state *gs = get_surface_state(view->surface); struct gl_surface_state *gs = get_surface_state(view->surface);
struct gl_output_state *go = get_output_state(output); struct gl_output_state *go = get_output_state(output);
struct gl_shader *shader;
bool ok;
if (!gl_renderer_use_program(gr, shader)) { ok = gl_renderer_use_program(gr, shaderp);
gl_renderer_send_shader_error(view); shader = *shaderp;
return;
}
glUniformMatrix4fv(shader->proj_uniform, glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, go->output_matrix.d); 1, GL_FALSE, go->output_matrix.d);
glUniform4fv(shader->color_uniform, 1, gs->color);
glUniform1f(shader->alpha_uniform, view->alpha);
for (i = 0; i < gs->num_textures; i++) if (ok) {
glUniform1i(shader->tex_uniforms[i], i); glUniform4fv(shader->color_uniform, 1, gs->color);
glUniform1f(shader->alpha_uniform, view->alpha);
for (i = 0; i < gs->num_textures; i++)
glUniform1i(shader->tex_uniforms[i], i);
} else {
gl_renderer_send_shader_error(view);
}
} }
static int static int
@ -988,7 +1023,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
if (gr->fan_debug) { if (gr->fan_debug) {
shader = gl_renderer_get_program(gr, shader = gl_renderer_get_program(gr,
&requirements_triangle_fan); &requirements_triangle_fan);
gl_renderer_use_program_with_view_uniforms(gr, shader, gl_renderer_use_program_with_view_uniforms(gr, &shader,
ev, output); ev, output);
} }
@ -1024,7 +1059,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
pixman_region32_copy(&surface_opaque, &ev->surface->opaque); pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
shader = maybe_censor_override(output, ev); shader = maybe_censor_override(output, ev);
gl_renderer_use_program_with_view_uniforms(gr, shader, ev, output); gl_renderer_use_program_with_view_uniforms(gr, &shader, ev, output);
if (pixman_region32_not_empty(&surface_opaque)) { if (pixman_region32_not_empty(&surface_opaque)) {
if (shader->key.variant == SHADER_VARIANT_RGBA) { if (shader->key.variant == SHADER_VARIANT_RGBA) {
@ -1040,7 +1075,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
tmp_requirements.variant = SHADER_VARIANT_RGBX; tmp_requirements.variant = SHADER_VARIANT_RGBX;
tmp_shader = gl_renderer_get_program(gr, &tmp_requirements); tmp_shader = gl_renderer_get_program(gr, &tmp_requirements);
gl_renderer_use_program_with_view_uniforms(gr, gl_renderer_use_program_with_view_uniforms(gr,
tmp_shader, &tmp_shader,
ev, output); ev, output);
} }
@ -1054,7 +1089,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
} }
if (pixman_region32_not_empty(&surface_blend)) { if (pixman_region32_not_empty(&surface_blend)) {
gl_renderer_use_program(gr, shader); gl_renderer_use_program(gr, &shader);
glEnable(GL_BLEND); glEnable(GL_BLEND);
repaint_region(ev, &repaint, &surface_blend); repaint_region(ev, &repaint, &surface_blend);
gs->used_in_output_repaint = true; gs->used_in_output_repaint = true;
@ -1251,7 +1286,7 @@ draw_output_borders(struct weston_output *output,
glDisable(GL_BLEND); glDisable(GL_BLEND);
shader = gl_renderer_get_program(gr, &requirements_rgba); shader = gl_renderer_get_program(gr, &requirements_rgba);
if (!gl_renderer_use_program(gr, shader)) if (!gl_renderer_use_program(gr, &shader))
return; return;
glViewport(0, 0, full_width, full_height); glViewport(0, 0, full_width, full_height);
@ -2823,7 +2858,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
} }
shader = gl_renderer_get_program(gr, &gs->shader_requirements); shader = gl_renderer_get_program(gr, &gs->shader_requirements);
if (!gl_renderer_use_program(gr, shader)) if (!gl_renderer_use_program(gr, &shader))
return -1; return -1;
glGenTextures(1, &tex); glGenTextures(1, &tex);
@ -3269,6 +3304,9 @@ gl_renderer_destroy(struct weston_compositor *ec)
wl_list_for_each_safe(shader, next_shader, &gr->shader_list, link) wl_list_for_each_safe(shader, next_shader, &gr->shader_list, link)
gl_shader_destroy(shader); gl_shader_destroy(shader);
if (gr->fallback_shader)
gl_shader_destroy(gr->fallback_shader);
/* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */ /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
eglMakeCurrent(gr->egl_display, eglMakeCurrent(gr->egl_display,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_SURFACE,
@ -3605,6 +3643,12 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
gr->fallback_shader = gl_renderer_create_fallback_shader(gr);
if (!gr->fallback_shader) {
weston_log("Error: compiling fallback shader failed.\n");
return -1;
}
gr->fragment_binding = gr->fragment_binding =
weston_compositor_add_debug_binding(ec, KEY_S, weston_compositor_add_debug_binding(ec, KEY_S,
fragment_debug_binding, fragment_debug_binding,

Loading…
Cancel
Save