From 7f6bcea3313b00580704258fb453b203a6b6b1a9 Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Fri, 20 May 2016 19:22:23 +0200 Subject: [PATCH] compositor: Handle GL video memory purged errors Emit a signal so that interested parties can recreate their FBOs and queue a full scene graph redraw to ensure we don't end up showing graphical artifacts. This relies on the GL driver supporting the NV_robustness_video_memory_purge extension and cogl creating a suitable GL context. For now we only make use of it with the X backend since the only driver with which this is useful is NVIDIA. https://bugzilla.gnome.org/show_bug.cgi?id=739178 --- src/backends/x11/meta-backend-x11.c | 2 ++ src/compositor/compositor-private.h | 1 + src/compositor/compositor.c | 28 ++++++++++++++++++++++++++-- src/core/display.c | 9 +++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index a645bbd08..089099633 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -884,6 +884,8 @@ meta_backend_x11_init (MetaBackendX11 *x11) { MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + clutter_x11_request_reset_on_video_memory_purge (); + /* We do X11 event retrieval ourselves */ clutter_x11_disable_event_retrieval (); diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 65fcec26e..c5349260c 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -31,6 +31,7 @@ struct _MetaCompositor CoglOnscreen *onscreen; CoglFrameClosure *frame_closure; + CoglContext *context; /* Used for unredirecting fullscreen windows */ guint disable_unredirect_count; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 30504aca2..b2f4f932e 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -1021,8 +1021,7 @@ frame_callback (CoglOnscreen *onscreen, * is fairly fast, so calling it twice and subtracting to get a * nearly-zero number is acceptable, if a litle ugly. */ - CoglContext *context = cogl_framebuffer_get_context (COGL_FRAMEBUFFER (onscreen)); - gint64 current_cogl_time = cogl_get_clock_time (context); + gint64 current_cogl_time = cogl_get_clock_time (compositor->context); gint64 current_monotonic_time = g_get_monotonic_time (); presentation_time = @@ -1052,6 +1051,7 @@ meta_pre_paint_func (gpointer data) frame_callback, compositor, NULL); + compositor->context = cogl_framebuffer_get_context (COGL_FRAMEBUFFER (compositor->onscreen)); } if (compositor->windows == NULL) @@ -1105,6 +1105,7 @@ static gboolean meta_post_paint_func (gpointer data) { MetaCompositor *compositor = data; + CoglGraphicsResetStatus status; if (compositor->frame_has_updated_xsurfaces) { @@ -1114,6 +1115,29 @@ meta_post_paint_func (gpointer data) compositor->frame_has_updated_xsurfaces = FALSE; } + status = cogl_get_graphics_reset_status (compositor->context); + switch (status) + { + case COGL_GRAPHICS_RESET_STATUS_NO_ERROR: + break; + + case COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET: + g_signal_emit_by_name (compositor->display, "gl-video-memory-purged"); + clutter_actor_queue_redraw (CLUTTER_ACTOR (compositor->stage)); + break; + + default: + /* The ARB_robustness spec says that, on error, the application + should destroy the old context and create a new one. Since we + don't have the necessary plumbing to do this we'll simply + restart the process. Obviously we can't do this when we are + a wayland compositor but in that case we shouldn't get here + since we don't enable robustness in that case. */ + g_assert (!meta_is_wayland_compositor ()); + meta_restart (NULL); + break; + } + return TRUE; } diff --git a/src/core/display.c b/src/core/display.c index 4c7a00eaf..a0a4b362f 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -125,6 +125,7 @@ enum SHOW_RESTART_MESSAGE, RESTART, SHOW_RESIZE_POPUP, + GL_VIDEO_MEMORY_PURGED, LAST_SIGNAL }; @@ -342,6 +343,14 @@ meta_display_class_init (MetaDisplayClass *klass) G_TYPE_BOOLEAN, 4, G_TYPE_BOOLEAN, META_TYPE_RECTANGLE, G_TYPE_INT, G_TYPE_INT); + display_signals[GL_VIDEO_MEMORY_PURGED] = + g_signal_new ("gl-video-memory-purged", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + g_object_class_install_property (object_class, PROP_FOCUS_WINDOW, g_param_spec_object ("focus-window",