[metacity] compositor: add MetaCompositorXPresent



commit bbf6760f9eab421bd558cbb45872ceafa033b21c
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Sep 12 20:01:06 2020 +0300

    compositor: add MetaCompositorXPresent
    
    https://gitlab.gnome.org/GNOME/metacity/-/issues/13

 .gitlab-ci.yml                            |   1 +
 configure.ac                              |   2 +-
 src/Makefile.am                           |   2 +
 src/compositor/meta-compositor-vulkan.c   |   1 +
 src/compositor/meta-compositor-xpresent.c | 281 ++++++++++++++++++++++++++++++
 src/compositor/meta-compositor-xpresent.h |  34 ++++
 src/core/display.c                        |   7 +
 src/include/meta-compositor.h             |   1 +
 8 files changed, 328 insertions(+), 1 deletion(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 205995ba..7a967c5b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,6 +30,7 @@ variables:
                   libxext-dev
                   libxfixes-dev
                   libxinerama-dev
+                  libxpresent-dev
                   libxrandr-dev
                   libxrender-dev
                   libxres-dev
diff --git a/configure.ac b/configure.ac
index e09b938d..9d15bdde 100644
--- a/configure.ac
+++ b/configure.ac
@@ -155,7 +155,7 @@ AC_CHECK_SIZEOF(__int64)
 ## byte order
 AC_C_BIGENDIAN
 
-METACITY_PC_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-2.0 >= $GLIB_REQUIRED_VERSION pango >= 
$PANGO_REQUIRED_VERSION gsettings-desktop-schemas >= 3.3.0 xcomposite >= $XCOMPOSITE_REQUIRED_VERSION xfixes 
xrender xdamage xres"
+METACITY_PC_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-2.0 >= $GLIB_REQUIRED_VERSION pango >= 
$PANGO_REQUIRED_VERSION gsettings-desktop-schemas >= 3.3.0 xcomposite >= $XCOMPOSITE_REQUIRED_VERSION xfixes 
xrender xdamage xres xpresent"
 
 GLIB_GSETTINGS
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 029e50b5..4f703eb3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,6 +33,8 @@ metacity_SOURCES = \
        compositor/meta-compositor-none.c \
        compositor/meta-compositor-none.h \
        compositor/meta-compositor-private.h \
+       compositor/meta-compositor-xpresent.c \
+       compositor/meta-compositor-xpresent.h \
        compositor/meta-compositor-xrender.c \
        compositor/meta-compositor-xrender.h \
        compositor/meta-shadow-xrender.c \
diff --git a/src/compositor/meta-compositor-vulkan.c b/src/compositor/meta-compositor-vulkan.c
index d543bbb2..44ab0d8d 100644
--- a/src/compositor/meta-compositor-vulkan.c
+++ b/src/compositor/meta-compositor-vulkan.c
@@ -1204,6 +1204,7 @@ not_implemented_cb (MetaCompositorVulkan *vulkan)
         compositor = "xrender";
         break;
 
+      case META_COMPOSITOR_TYPE_XPRESENT:
       case META_COMPOSITOR_TYPE_EXTERNAL:
       case META_COMPOSITOR_TYPE_VULKAN:
       default:
diff --git a/src/compositor/meta-compositor-xpresent.c b/src/compositor/meta-compositor-xpresent.c
new file mode 100644
index 00000000..3e610a9d
--- /dev/null
+++ b/src/compositor/meta-compositor-xpresent.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "meta-compositor-xpresent.h"
+
+#include <X11/extensions/Xpresent.h>
+
+#include "display-private.h"
+#include "errors.h"
+#include "screen-private.h"
+
+#define NUM_BUFFER 2
+
+struct _MetaCompositorXPresent
+{
+  MetaCompositorXRender parent;
+
+  int                   major_opcode;
+  int                   event_base;
+  int                   error_base;
+
+  Picture               root_buffers[NUM_BUFFER];
+  Pixmap                root_pixmaps[NUM_BUFFER];
+  int                   root_current;
+
+  gboolean              present_pending;
+};
+
+G_DEFINE_TYPE (MetaCompositorXPresent,
+               meta_compositor_xpresent,
+               META_TYPE_COMPOSITOR_XRENDER)
+
+static gboolean
+meta_compositor_xpresent_manage (MetaCompositor  *compositor,
+                                 GError         **error)
+{
+  MetaCompositorClass *compositor_class;
+  MetaCompositorXPresent *self;
+  MetaDisplay *display;
+  Display *xdisplay;
+
+  compositor_class = META_COMPOSITOR_CLASS (meta_compositor_xpresent_parent_class);
+
+  if (!compositor_class->manage (compositor, error))
+    return FALSE;
+
+  self = META_COMPOSITOR_XPRESENT (compositor);
+
+  display = meta_compositor_get_display (compositor);
+  xdisplay = meta_display_get_xdisplay (display);
+
+  if (!XPresentQueryExtension (xdisplay,
+                               &self->major_opcode,
+                               &self->event_base,
+                               &self->error_base))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Missing present extension required for compositing");
+
+      return FALSE;
+    }
+
+  XPresentSelectInput (xdisplay,
+                       meta_compositor_get_overlay_window (compositor),
+                       PresentCompleteNotifyMask);
+
+  return TRUE;
+}
+
+static void
+meta_compositor_xpresent_process_event (MetaCompositor *compositor,
+                                        XEvent         *event,
+                                        MetaWindow     *window)
+{
+  MetaCompositorXPresent *self;
+  MetaCompositorClass *compositor_class;
+
+  self = META_COMPOSITOR_XPRESENT (compositor);
+
+  if (event->type == GenericEvent)
+    {
+      XGenericEvent *generic_event;
+      XGenericEventCookie *generic_event_cookie;
+      MetaDisplay *display;
+      Display *xdisplay;
+
+      generic_event = (XGenericEvent *) event;
+      generic_event_cookie = (XGenericEventCookie *) generic_event;
+
+      display = meta_compositor_get_display (compositor);
+      xdisplay = meta_display_get_xdisplay (display);
+
+      if (generic_event_cookie->extension == self->major_opcode)
+        {
+          XGetEventData (xdisplay, generic_event_cookie);
+
+          if (generic_event_cookie->evtype == PresentCompleteNotify)
+            {
+              meta_compositor_queue_redraw (compositor);
+              self->present_pending = FALSE;
+            }
+
+          XFreeEventData (xdisplay, generic_event_cookie);
+        }
+    }
+
+  compositor_class = META_COMPOSITOR_CLASS (meta_compositor_xpresent_parent_class);
+  compositor_class->process_event (compositor, event, window);
+}
+
+static gboolean
+meta_compositor_xpresent_ready_to_redraw (MetaCompositor *compositor)
+{
+  MetaCompositorXPresent *self;
+
+  self = META_COMPOSITOR_XPRESENT (compositor);
+
+  return !self->present_pending;
+}
+
+static void
+meta_compositor_xpresent_redraw (MetaCompositor *compositor,
+                                 XserverRegion   all_damage)
+{
+  MetaCompositorXPresent *self;
+  MetaDisplay *display;
+  Display *xdisplay;
+  int result;
+
+  self = META_COMPOSITOR_XPRESENT (compositor);
+
+  display = meta_compositor_get_display (META_COMPOSITOR (self));
+  xdisplay = meta_display_get_xdisplay (display);
+
+  meta_compositor_xrender_draw (META_COMPOSITOR_XRENDER (compositor),
+                                self->root_buffers[self->root_current],
+                                all_damage);
+
+  meta_error_trap_push (display);
+
+  XPresentPixmap (xdisplay,
+                  meta_compositor_get_overlay_window (compositor),
+                  self->root_pixmaps[self->root_current],
+                  0,
+                  all_damage,
+                  all_damage,
+                  0,
+                  0,
+                  None,
+                  None,
+                  None,
+                  PresentOptionNone,
+                  0,
+                  1,
+                  0,
+                  NULL,
+                  0);
+
+  result = meta_error_trap_pop_with_return (display);
+
+  if (result != Success)
+    {
+      char error_text[64];
+
+      XGetErrorText (xdisplay, result, error_text, 63);
+
+      g_warning ("XPresentPixmap failed with error %i (%s)",
+                 result, error_text);
+
+      g_unsetenv ("META_COMPOSITOR");
+      meta_display_update_compositor (display);
+
+      return;
+    }
+
+  self->root_current = !self->root_current;
+  self->present_pending = TRUE;
+}
+
+static void
+meta_compositor_xpresent_ensure_root_buffers (MetaCompositorXRender *xrender)
+{
+  MetaCompositorXPresent *self;
+  int i;
+
+  self = META_COMPOSITOR_XPRESENT (xrender);
+
+  for (i = 0; i < NUM_BUFFER; i++)
+    {
+      if (self->root_buffers[i] == None &&
+          self->root_pixmaps[i] == None)
+        {
+          meta_compositor_xrender_create_root_buffer (xrender,
+                                                      &self->root_pixmaps[i],
+                                                      &self->root_buffers[i]);
+        }
+    }
+}
+
+static void
+meta_compositor_xpresent_free_root_buffers (MetaCompositorXRender *xrender)
+{
+  MetaCompositorXPresent *self;
+  MetaDisplay *display;
+  Display *xdisplay;
+  int i;
+
+  self = META_COMPOSITOR_XPRESENT (xrender);
+
+  display = meta_compositor_get_display (META_COMPOSITOR (self));
+  xdisplay = meta_display_get_xdisplay (display);
+
+  for (i = 0; i < NUM_BUFFER; i++)
+    {
+      if (self->root_buffers[i] != None)
+        {
+          XRenderFreePicture (xdisplay, self->root_buffers[i]);
+          self->root_buffers[i] = None;
+        }
+
+      if (self->root_pixmaps[i] != None)
+        {
+          XFreePixmap (xdisplay, self->root_pixmaps[i]);
+          self->root_pixmaps[i] = None;
+        }
+    }
+}
+
+static void
+meta_compositor_xpresent_class_init (MetaCompositorXPresentClass *self_class)
+{
+  MetaCompositorClass *compositor_class;
+  MetaCompositorXRenderClass *xrender_class;
+
+  compositor_class = META_COMPOSITOR_CLASS (self_class);
+  xrender_class = META_COMPOSITOR_XRENDER_CLASS (self_class);
+
+  compositor_class->manage = meta_compositor_xpresent_manage;
+  compositor_class->process_event = meta_compositor_xpresent_process_event;
+  compositor_class->ready_to_redraw = meta_compositor_xpresent_ready_to_redraw;
+  compositor_class->redraw = meta_compositor_xpresent_redraw;
+
+  xrender_class->ensure_root_buffers = meta_compositor_xpresent_ensure_root_buffers;
+  xrender_class->free_root_buffers = meta_compositor_xpresent_free_root_buffers;
+}
+
+static void
+meta_compositor_xpresent_init (MetaCompositorXPresent *self)
+{
+  int i;
+
+  for (i = 0; i < NUM_BUFFER; i++)
+    {
+      self->root_buffers[i] = None;
+      self->root_pixmaps[i] = None;
+    }
+}
+
+MetaCompositor *
+meta_compositor_xpresent_new (MetaDisplay  *display,
+                              GError      **error)
+{
+  return g_initable_new (META_TYPE_COMPOSITOR_XPRESENT, NULL, error,
+                         "display", display,
+                         NULL);
+}
diff --git a/src/compositor/meta-compositor-xpresent.h b/src/compositor/meta-compositor-xpresent.h
new file mode 100644
index 00000000..1c7bf5d4
--- /dev/null
+++ b/src/compositor/meta-compositor-xpresent.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef META_COMPOSITOR_XPRESENT_H
+#define META_COMPOSITOR_XPRESENT_H
+
+#include "meta-compositor-xrender.h"
+
+G_BEGIN_DECLS
+
+#define META_TYPE_COMPOSITOR_XPRESENT (meta_compositor_xpresent_get_type ())
+G_DECLARE_FINAL_TYPE (MetaCompositorXPresent, meta_compositor_xpresent,
+                      META, COMPOSITOR_XPRESENT, MetaCompositorXRender)
+
+MetaCompositor *meta_compositor_xpresent_new (MetaDisplay  *display,
+                                              GError      **error);
+
+G_END_DECLS
+
+#endif
diff --git a/src/core/display.c b/src/core/display.c
index e05ea467..75db10a8 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -68,6 +68,7 @@
 
 #include "compositor/meta-compositor-none.h"
 #include "compositor/meta-compositor-xrender.h"
+#include "compositor/meta-compositor-xpresent.h"
 #include "compositor/meta-compositor-external.h"
 
 #ifdef HAVE_VULKAN
@@ -278,6 +279,8 @@ get_compositor_type (MetaDisplay *display)
         type = META_COMPOSITOR_TYPE_VULKAN;
       else if (g_strcmp0 (compositor, "xrender") == 0)
         type = META_COMPOSITOR_TYPE_XRENDER;
+      else if (g_strcmp0 (compositor, "xpresent") == 0)
+        type = META_COMPOSITOR_TYPE_XPRESENT;
       else if (g_strcmp0 (compositor, "external") == 0)
         type = META_COMPOSITOR_TYPE_EXTERNAL;
       else
@@ -310,6 +313,10 @@ create_compositor (MetaDisplay         *display,
         compositor = meta_compositor_xrender_new (display, error);
         break;
 
+      case META_COMPOSITOR_TYPE_XPRESENT:
+        compositor = meta_compositor_xpresent_new (display, error);
+        break;
+
       case META_COMPOSITOR_TYPE_EXTERNAL:
         compositor = meta_compositor_external_new (display, error);
         break;
diff --git a/src/include/meta-compositor.h b/src/include/meta-compositor.h
index ee84f907..9e0778a6 100644
--- a/src/include/meta-compositor.h
+++ b/src/include/meta-compositor.h
@@ -35,6 +35,7 @@ typedef enum
 {
   META_COMPOSITOR_TYPE_NONE,
   META_COMPOSITOR_TYPE_XRENDER,
+  META_COMPOSITOR_TYPE_XPRESENT, /*< skip >*/
   META_COMPOSITOR_TYPE_EXTERNAL, /*< skip >*/
   META_COMPOSITOR_TYPE_VULKAN /*< skip >*/
 } MetaCompositorType;


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