Package: gnome-shell
Version: 3.14.2-3+b1
Severity: normal
Tags: upstream

Dear Maintainer,

The proprietary NVIDIA driver has a bug where it doesn't preserve OpenGL frame buffer objects (FBOs) across power events (most noticeably across a suspend/resume cycle). This is reported in Debian as bug https://bugs.debian.org/761360 (and a couple others that got merged into that), and upstream as https://bugzilla.gnome.org/739178. GNOME started storing the backgrounds for the desktop and lock screen in FBOs in 3.14, which is why the issue didn't show up before 3.14.

This is NVIDIA's problem, of course, and NVIDIA has admitted as much, but the word from NVIDIA is just that this will be fixed at some indeterminate point "in the future."

In the meantime, upstream has applied a patch included in the 3.14.4 releases of gnome-shell and mutter, and will also include this fix in the 3.16.1 release. The patch adds an ability to mutter to redraw all FBO background instances, and invokes this from gnome-shell during resume.

The upstream patches (reattached here) apply to the gnome-shell and mutter versions currently in sid/testing. I've rebuilt the packages locally (on amd64/unstable) with the patches applied, and can confirm that this does work around the problem with the proprietary NVIDIA driver.

It would be nice for proprietary NVIDIA jessie users if we could get these patches applied to jessie as well, perhaps for the first jessie point update, either with a package update to 3.14.4, or by applying these patches to the current 3.14.2 version: this is going to be an issue that affects a lot of jessie users, and it doesn't sound as though NVIDIA is particularly concerned about fixing it in the immediate future.

The upstream patches are attached here for convenience: background-instance-refresh.patch is the mutter side of the fix, refresh-bg-after-suspend.patch is the gnome-shell side of the fix.

Thanks,

Jason Rhinelander
From c96f57449f1cdc60162f6bbcc82d504fde5c1f76 Mon Sep 17 00:00:00 2001
From: Rui Matos <tiagoma...@gmail.com>
Date: Thu, 19 Mar 2015 14:58:25 +0100
Subject: [PATCH] meta-background: Add a function to refresh all background
 instances

We need to reload the FBOs under some circumstances, this adds a way
to easily do so.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
---
 src/compositor/meta-background.c | 14 ++++++++++++++
 src/meta/meta-background.h       |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c
index 6284a7a..3f2e23f 100644
--- a/src/compositor/meta-background.c
+++ b/src/compositor/meta-background.c
@@ -71,6 +71,8 @@ enum
 
 G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
 
+static GSList *all_backgrounds = NULL;
+
 static void
 free_fbos (MetaBackground *self)
 {
@@ -305,6 +307,8 @@ meta_background_dispose (GObject *object)
 static void
 meta_background_finalize (GObject *object)
 {
+  all_backgrounds = g_slist_remove (all_backgrounds, object);
+
   G_OBJECT_CLASS (meta_background_parent_class)->finalize (object);
 }
 
@@ -347,6 +351,7 @@ meta_background_init (MetaBackground *self)
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
                                             META_TYPE_BACKGROUND,
                                             MetaBackgroundPrivate);
+  all_backgrounds = g_slist_prepend (all_backgrounds, self);
 }
 
 static void
@@ -913,3 +918,12 @@ meta_background_set_blend (MetaBackground          *self,
   free_wallpaper_texture (self);
   mark_changed (self);
 }
+
+void
+meta_background_refresh_all (void)
+{
+  GSList *l;
+
+  for (l = all_backgrounds; l; l = l->next)
+    mark_changed (l->data);
+}
diff --git a/src/meta/meta-background.h b/src/meta/meta-background.h
index 822d27b..d48d966 100644
--- a/src/meta/meta-background.h
+++ b/src/meta/meta-background.h
@@ -57,6 +57,8 @@ struct _MetaBackground
   MetaBackgroundPrivate *priv;
 };
 
+void meta_background_refresh_all (void);
+
 GType meta_background_get_type (void);
 
 MetaBackground *meta_background_new  (MetaScreen *screen);
-- 
2.1.0
From d19e78af2459b1b5165848b643525df29ee20265 Mon Sep 17 00:00:00 2001
From: Rui Matos <tiagoma...@gmail.com>
Date: Thu, 19 Mar 2015 15:46:08 +0100
Subject: [PATCH] Refresh all background instances after suspend if needed

NVIDIA drivers don't preserve FBO contents across suspend / resume
cycles which results in broken backgrounds. We can work around that by
forcing a refresh when coming out of suspend.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
---
 js/ui/layout.js  | 13 +++++++++++++
 src/shell-util.c | 33 +++++++++++++++++++++++++++++++++
 src/shell-util.h |  2 ++
 3 files changed, 48 insertions(+)

diff --git a/js/ui/layout.js b/js/ui/layout.js
index 9228bd1..e9aab13 100644
--- a/js/ui/layout.js
+++ b/js/ui/layout.js
@@ -11,6 +11,7 @@ const St = imports.gi.St;
 
 const Background = imports.ui.background;
 const BackgroundMenu = imports.ui.backgroundMenu;
+const LoginManager = imports.misc.loginManager;
 
 const DND = imports.ui.dnd;
 const Main = imports.ui.main;
@@ -248,6 +249,18 @@ const LayoutManager = new Lang.Class({
         global.screen.connect('in-fullscreen-changed',
                               Lang.bind(this, this._updateFullscreen));
         this._monitorsChanged();
+
+        // NVIDIA drivers don't preserve FBO contents across
+        // suspend/resume, see
+        // https://bugzilla.gnome.org/show_bug.cgi?id=739178
+        if (Shell.util_need_background_refresh()) {
+            LoginManager.getLoginManager().connect('prepare-for-sleep',
+                                                   function(lm, suspending) {
+                                                       if (suspending)
+                                                           return;
+                                                       Meta.Background.refresh_all();
+                                                   });
+        }
     },
 
     // This is called by Main after everything else is constructed
diff --git a/src/shell-util.c b/src/shell-util.c
index 5ae4fdb..8792403 100644
--- a/src/shell-util.c
+++ b/src/shell-util.c
@@ -5,6 +5,9 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include <GL/gl.h>
+#include <cogl/cogl.h>
+
 #include "shell-util.h"
 #include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
@@ -330,3 +333,33 @@ shell_util_cursor_tracker_to_clutter (MetaCursorTracker *tracker,
       clutter_actor_hide (CLUTTER_ACTOR (texture));
     }
 }
+
+typedef const gchar *(*ShellGLGetString) (GLenum);
+
+static const gchar *
+get_gl_vendor (void)
+{
+  static const gchar *vendor = NULL;
+
+  if (!vendor)
+    {
+      ShellGLGetString gl_get_string;
+      gl_get_string = (ShellGLGetString) cogl_get_proc_address ("glGetString");
+      if (gl_get_string)
+        vendor = gl_get_string (GL_VENDOR);
+    }
+
+  return vendor;
+}
+
+gboolean
+shell_util_need_background_refresh (void)
+{
+  if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
+    return FALSE;
+
+  if (g_strcmp0 (get_gl_vendor (), "NVIDIA Corporation") == 0)
+    return TRUE;
+
+  return FALSE;
+}
diff --git a/src/shell-util.h b/src/shell-util.h
index d7ab4fd..be20083 100644
--- a/src/shell-util.h
+++ b/src/shell-util.h
@@ -44,6 +44,8 @@ GdkPixbuf *shell_util_create_pixbuf_from_data (const guchar      *data,
 void    shell_util_cursor_tracker_to_clutter (MetaCursorTracker *tracker,
                                               ClutterTexture    *texture);
 
+gboolean shell_util_need_background_refresh (void);
+
 G_END_DECLS
 
 #endif /* __SHELL_UTIL_H__ */
--
2.1.0

Reply via email to