[mutter/wip/texture-purge-on-nvidia: 66/66] wip! force texture updates



commit f054da317f78ee398af2b2f41a3f0edcee97ed6b
Author: Ray Strode <rstrode redhat com>
Date:   Tue Jan 8 16:51:28 2019 -0500

    wip! force texture updates
    
    This unfinished commit makes sure all the various texture caches
    get flushed on resume, so they don't leave corruption on the
    screen with nvidia proprietary driver.
    
    There's still no answer for client redraws, but I think maybe we
    can fudge it near term, by messing with the output scale factor
    or some other trick like that.
    
    Also, this needs to conditionalize the code so it only runs for
    nvidia. That's something i'm going to experiment with next.
    
    The code detects resume via timerfd instead of ARB_robustness, so
    we don't lose our context. that code needs to be conditionalized,
    so it doesn't try to build on platforms that don't have timerfd.
    
    This whole commit needs to be broken up into subcommits.

 src/Makefile.am                             |   2 +
 src/compositor/compositor-private.h         |   3 +
 src/compositor/compositor.c                 |  36 +++++-
 src/compositor/meta-surface-actor-wayland.c |   2 +
 src/compositor/meta-suspend-monitor.c       | 181 ++++++++++++++++++++++++++++
 src/compositor/meta-suspend-monitor.h       |  53 ++++++++
 6 files changed, 275 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 0606efac5..536deb60d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -252,6 +252,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =      \
        compositor/meta-surface-actor.h         \
        compositor/meta-surface-actor-x11.c     \
        compositor/meta-surface-actor-x11.h     \
+       compositor/meta-suspend-monitor.c       \
+       compositor/meta-suspend-monitor.h       \
        compositor/meta-sync-ring.c             \
        compositor/meta-sync-ring.h             \
        compositor/meta-texture-rectangle.c     \
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index 40c0344cc..c52e49ea0 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -8,6 +8,7 @@
 #include <meta/compositor.h>
 #include <meta/display.h>
 #include "meta-plugin-manager.h"
+#include "meta-suspend-monitor.h"
 #include "meta-window-actor-private.h"
 #include <clutter/clutter.h>
 
@@ -41,6 +42,8 @@ struct _MetaCompositor
 
   MetaPluginManager *plugin_mgr;
 
+  MetaSuspendMonitor *suspend_monitor;
+
   gboolean frame_has_updated_xsurfaces;
   gboolean have_x11_sync_object;
 };
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 8c924d256..15c17c2cc 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -54,6 +54,8 @@
 
 #include <clutter/x11/clutter-x11.h>
 
+#include <sys/timerfd.h>
+
 #include "core.h"
 #include <meta/screen.h>
 #include <meta/errors.h>
@@ -89,6 +91,9 @@ on_presented (ClutterStage     *stage,
               CoglFrameEvent    event,
               ClutterFrameInfo *frame_info,
               MetaCompositor   *compositor);
+static void
+on_resumed (MetaSuspendMonitor *monitor,
+            MetaCompositor     *compositor);
 
 static gboolean
 is_modal (MetaDisplay *display)
@@ -503,6 +508,12 @@ meta_compositor_manage (MetaCompositor *compositor)
                     G_CALLBACK (on_presented),
                     compositor);
 
+  compositor->suspend_monitor = meta_suspend_monitor_new ();
+
+  g_signal_connect (compositor->suspend_monitor, "resumed",
+                   G_CALLBACK (on_resumed),
+                   compositor);
+
   /* We use connect_after() here to accomodate code in GNOME Shell that,
    * when benchmarking drawing performance, connects to ::after-paint
    * and calls glFinish(). The timing information from that will be
@@ -580,6 +591,8 @@ meta_compositor_unmanage (MetaCompositor *compositor)
        * window manager won't be able to redirect subwindows */
       XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
     }
+
+  g_clear_object (&compositor->suspend_monitor);
 }
 
 /**
@@ -1175,6 +1188,25 @@ meta_pre_paint_func (gpointer data)
   return TRUE;
 }
 
+static void
+purge_textures (MetaCompositor *compositor)
+{
+  clutter_clear_glyph_cache ();
+  g_signal_emit_by_name (compositor->display, "gl-video-memory-purged");
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (compositor->stage));
+}
+
+static void
+on_resumed (MetaSuspendMonitor *monitor,
+            MetaCompositor     *compositor)
+{
+  MetaDisplay *display = compositor->display;
+
+  purge_textures (compositor);
+
+  meta_screen_update_cursor (display->screen);
+}
+
 static gboolean
 meta_post_paint_func (gpointer data)
 {
@@ -1190,14 +1222,14 @@ meta_post_paint_func (gpointer data)
     }
 
   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));
+      purge_textures (compositor);
       break;
 
     default:
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
index 7505b7d79..7b00b68a2 100644
--- a/src/compositor/meta-surface-actor-wayland.c
+++ b/src/compositor/meta-surface-actor-wayland.c
@@ -228,6 +228,8 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
 static void
 meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self)
 {
+  MetaSurfaceActorWaylandPrivate *priv =
+    meta_surface_actor_wayland_get_instance_private (self);
 }
 
 MetaSurfaceActor *
diff --git a/src/compositor/meta-suspend-monitor.c b/src/compositor/meta-suspend-monitor.c
new file mode 100644
index 000000000..64c2b08e7
--- /dev/null
+++ b/src/compositor/meta-suspend-monitor.c
@@ -0,0 +1,181 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright © 2012 – 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <sys/timerfd.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixinputstream.h>
+
+#include "meta-suspend-monitor.h"
+
+struct _MetaSuspendMonitorPrivate
+{
+  GSource *timer_source;
+  GInputStream *timer_stream;
+};
+
+enum
+{
+  RESUMED,
+  NUMBER_OF_SIGNALS,
+};
+
+static guint signals[NUMBER_OF_SIGNALS] = { 0 };
+
+G_DEFINE_TYPE_WITH_PRIVATE (MetaSuspendMonitor, meta_suspend_monitor, G_TYPE_OBJECT);
+
+static gboolean schedule_indefinite_wakeup (MetaSuspendMonitor *self);
+
+static void
+meta_suspend_monitor_dispose (GObject *object)
+{
+  MetaSuspendMonitor *self = META_SUSPEND_MONITOR (object);
+
+  g_clear_pointer (&self->priv->timer_source, g_source_destroy);
+  g_clear_object (&self->priv->timer_stream);
+
+  G_OBJECT_CLASS (meta_suspend_monitor_parent_class)->dispose (object);
+}
+
+static void
+meta_suspend_monitor_class_init (MetaSuspendMonitorClass *klass)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = meta_suspend_monitor_dispose;
+
+  signals[RESUMED] = g_signal_new ("resumed",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_SIGNAL_RUN_LAST,
+                                   0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+static gboolean
+on_timer_source_ready (GObject            *timer_stream,
+                       MetaSuspendMonitor *self)
+{
+  gint64 number_of_fires;
+  gssize bytes_read;
+  GError *error = NULL;
+
+  g_return_val_if_fail (META_IS_SUSPEND_MONITOR (self), FALSE);
+
+  bytes_read =
+    g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (timer_stream),
+                                              &number_of_fires, sizeof (gint64),
+                                              NULL, &error);
+
+  if (bytes_read < 0 )
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_signal_emit (self, signals[RESUMED], 0);
+        }
+      else
+        {
+          g_warning ("MetaSuspendMonitor: failed to read from timer fd: %s\n",
+                     error->message);
+          goto out;
+        }
+    }
+
+  schedule_indefinite_wakeup (self);
+out:
+  g_error_free (error);
+  return FALSE;
+}
+
+static void
+clear_wakeup_source_pointer (MetaSuspendMonitor *self)
+{
+  self->priv->timer_source = NULL;
+}
+
+static gboolean
+schedule_indefinite_wakeup (MetaSuspendMonitor *self)
+{
+  struct itimerspec timer_spec;
+  int fd;
+  int result;
+  GSource *source;
+
+  fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK);
+
+  if (fd < 0)
+    {
+      g_warning ("MetaSuspendMonitor: could not create timer fd: %s", strerror (errno));
+      return FALSE;
+    }
+
+  memset (&timer_spec, 0, sizeof (timer_spec));
+
+  /* set the timer for the distant future, so it only wakes up on resume */
+  timer_spec.it_value.tv_sec = LONG_MAX;
+
+  result = timerfd_settime (fd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &timer_spec, NULL);
+
+  if (result < 0)
+    {
+      g_warning ("MetaSuspendMonitor: could not set timer: %s", strerror (errno));
+      return FALSE;
+    }
+
+  g_clear_object (&self->priv->timer_stream);
+
+  self->priv->timer_stream = g_unix_input_stream_new (fd, TRUE);
+
+  source =
+    g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (self->priv->timer_stream),
+                                           NULL);
+  g_clear_pointer (&self->priv->timer_source,
+                   g_source_destroy);
+  self->priv->timer_source = source;
+  g_source_set_callback (self->priv->timer_source,
+                         (GSourceFunc) on_timer_source_ready, self,
+                         (GDestroyNotify) clear_wakeup_source_pointer);
+  g_source_attach (self->priv->timer_source, NULL);
+  g_source_unref (source);
+
+  return TRUE;
+}
+
+static void
+meta_suspend_monitor_init (MetaSuspendMonitor *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, META_TYPE_SUSPEND_MONITOR, MetaSuspendMonitorPrivate);
+
+  schedule_indefinite_wakeup (self);
+}
+
+MetaSuspendMonitor *
+meta_suspend_monitor_new (void)
+{
+  MetaSuspendMonitor *self;
+
+  self = META_SUSPEND_MONITOR (g_object_new (META_TYPE_SUSPEND_MONITOR, NULL));
+
+  return self;
+}
diff --git a/src/compositor/meta-suspend-monitor.h b/src/compositor/meta-suspend-monitor.h
new file mode 100644
index 000000000..5a2e40137
--- /dev/null
+++ b/src/compositor/meta-suspend-monitor.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __META_SUSPEND_MONITOR_H__
+#define __META_SUSPEND_MONITOR_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+#define META_TYPE_SUSPEND_MONITOR             (meta_suspend_monitor_get_type ())
+#define META_SUSPEND_MONITOR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SUSPEND_MONITOR, 
MetaSuspendMonitor))
+#define META_SUSPEND_MONITOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SUSPEND_MONITOR, 
MetaSuspendMonitorClass))
+#define META_IS_SUSPEND_MONITOR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SUSPEND_MONITOR))
+#define META_IS_SUSPEND_MONITOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SUSPEND_MONITOR))
+#define META_SUSPEND_MONITOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), META_TYPE_SUSPEND_MONITOR, 
MetaSuspendMonitorClass))
+typedef struct _MetaSuspendMonitor MetaSuspendMonitor;
+typedef struct _MetaSuspendMonitorClass MetaSuspendMonitorClass;
+typedef struct _MetaSuspendMonitorPrivate MetaSuspendMonitorPrivate;
+
+struct _MetaSuspendMonitor
+{
+  GObject parent;
+
+  MetaSuspendMonitorPrivate *priv;
+};
+
+struct _MetaSuspendMonitorClass
+{
+  GObjectClass parent_class;
+};
+
+GType meta_suspend_monitor_get_type (void);
+
+MetaSuspendMonitor *meta_suspend_monitor_new (void);
+G_END_DECLS
+#endif /* __META_SUSPEND_MONITOR_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]