From bdcd59fd6c5e5a2d452b9caebddc5ca45af51d2f Mon Sep 17 00:00:00 2001
From: Bilal Elmoussaoui <belmouss@redhat.com>
Date: Mon, 2 Oct 2023 16:51:17 +0200
Subject: [PATCH 1/3] dmabuf paintable: Switch to GdkDmabufTexture

---
 .gitlab-ci.yml                     |   4 +-
 lib/meson.build                    |   2 -
 lib/mks-display.c                  |   1 +
 lib/mks-dmabuf-paintable-private.h |   2 +-
 lib/mks-dmabuf-paintable.c         | 104 +++++------------
 lib/mks-gl-context-private.h       |  39 -------
 lib/mks-gl-context.c               | 176 -----------------------------
 lib/mks-paintable-private.h        |   3 +-
 lib/mks-paintable.c                |  32 ++----
 lib/mks-screen.c                   |   7 +-
 lib/mks-screen.h                   |   2 +
 meson.build                        |   3 +-
 12 files changed, 50 insertions(+), 325 deletions(-)
 delete mode 100644 lib/mks-gl-context-private.h
 delete mode 100644 lib/mks-gl-context.c

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a261ec9..790c201 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -13,7 +13,7 @@ tests:
   variables:
     MESON_FLAGS: "-Db_coverage=true -Ddocs=false -Dvapi=false -Dintrospection=disabled"
   before_script:
-    - sudo dnf install -y git gtk4-devel libepoxy-devel meson gcc lcov wget
+    - sudo dnf install -y git gtk4-devel meson gcc lcov wget
       qemu-system-x86 qemu-ui-dbus qemu-ui-opengl
       dbus-x11 xorg-x11-server-Xvfb
   script:
@@ -46,7 +46,7 @@ reference:
   variables:
     MESON_FLAGS: "--buildtype=release -Ddocs=true -Dintrospection=enabled"
   before_script:
-    - sudo dnf install -y git gtk4-devel libepoxy-devel meson gcc
+    - sudo dnf install -y git gtk4-devel meson gcc
       gi-docgen gobject-introspection-devel vala
   script:
     - mkdir -p pfx/
diff --git a/lib/meson.build b/lib/meson.build
index 3ad20be..03e491b 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -45,7 +45,6 @@ libmks_private_sources = [
   'mks-dmabuf-paintable.c',
   'mks-display-picture.c',
   'mks-css.c',
-  'mks-gl-context.c',
   'mks-inhibitor.c',
   'mks-read-only-list-model.c',
   'mks-screen-resizer.c',
@@ -120,7 +119,6 @@ libmks_private_generated_headers = [
 ]
 
 libmks_deps = [
-  libepoxy_dep,
   libgio_dep,
   libgiounix_dep,
   libgtk_dep,
diff --git a/lib/mks-display.c b/lib/mks-display.c
index 880d06f..3094ba7 100644
--- a/lib/mks-display.c
+++ b/lib/mks-display.c
@@ -145,6 +145,7 @@ mks_display_connect (MksDisplay *self,
       mks_screen_resizer_set_screen (priv->resizer, screen);
 
       mks_screen_attach (screen,
+                         gtk_widget_get_display (GTK_WIDGET (self)),
                          NULL,
                          mks_display_attach_cb,
                          g_object_ref (self));
diff --git a/lib/mks-dmabuf-paintable-private.h b/lib/mks-dmabuf-paintable-private.h
index 515c9f4..42623cf 100644
--- a/lib/mks-dmabuf-paintable-private.h
+++ b/lib/mks-dmabuf-paintable-private.h
@@ -42,7 +42,7 @@ G_DECLARE_FINAL_TYPE (MksDmabufPaintable, mks_dmabuf_paintable, MKS, DMABUF_PAIN
 
 MksDmabufPaintable *mks_dmabuf_paintable_new        (void);
 gboolean            mks_dmabuf_paintable_import     (MksDmabufPaintable   *self,
-                                                     GdkGLContext         *gl_context,
+                                                     GdkDisplay           *display,
                                                      MksDmabufScanoutData *data,
                                                      cairo_region_t       *region,
                                                      GError              **error);
diff --git a/lib/mks-dmabuf-paintable.c b/lib/mks-dmabuf-paintable.c
index 0225e56..a4895e2 100644
--- a/lib/mks-dmabuf-paintable.c
+++ b/lib/mks-dmabuf-paintable.c
@@ -25,62 +25,25 @@
 #include <gtk/gtk.h>
 
 #include "mks-dmabuf-paintable-private.h"
-#include "mks-gl-context-private.h"
 
 /*
  * MksDmabufPaintable is a GdkPaintable that gets created the first time
  * `ScanoutDMABUF` is called.
  *
  * The scanout data is then stored until we receive a `UpdateDMABUF` call
- * so we can pass the damage region to `GdkGLTextureBuilder`.
+ * so we can pass the damage region to `GdkDmabufTextureBuilder`.
  */
 
-typedef struct _MksDmabufTextureData
-{
-  GdkGLContext *gl_context;
-  GLuint texture_id;
-} MksDmabufTextureData;
-
 struct _MksDmabufPaintable
 {
   GObject parent_instance;
   GdkTexture *texture;
-  GdkGLTextureBuilder *builder;
+  GdkDmabufTextureBuilder *builder;
   guint width;
   guint height;
   guint dmabuf_updated : 1;
 };
 
-static MksDmabufTextureData *
-mks_dmabuf_texture_data_new (GdkGLContext *gl_context,
-                             GLuint        texture_id)
-{
-  MksDmabufTextureData *texture_data;
-
-  g_assert (GDK_IS_GL_CONTEXT (gl_context));
-  g_assert (texture_id > 0);
-
-  texture_data = g_new0 (MksDmabufTextureData, 1);
-  texture_data->gl_context = g_object_ref (gl_context);
-  texture_data->texture_id = texture_id;
-
-  return texture_data;
-}
-
-static void
-mks_dmabuf_texture_data_free (gpointer data)
-{
-  MksDmabufTextureData *texture_data = data;
-
-  gdk_gl_context_make_current (texture_data->gl_context);
-  glDeleteTextures (1, &texture_data->texture_id);
-
-  texture_data->texture_id = 0;
-  g_clear_object (&texture_data->gl_context);
-
-  g_free (texture_data);
-}
-
 static int
 mks_dmabuf_paintable_get_intrinsic_width (GdkPaintable *paintable)
 {
@@ -112,8 +75,7 @@ mks_dmabuf_paintable_snapshot (GdkPaintable *paintable,
 {
   MksDmabufPaintable *self = (MksDmabufPaintable *)paintable;
   g_autoptr(GdkTexture) texture = NULL;
-  GdkGLContext *gl_context;
-  GLuint texture_id;
+  g_autoptr(GError) error = NULL;
   graphene_rect_t area;
 
   g_assert (MKS_IS_DMABUF_PAINTABLE (self));
@@ -122,21 +84,22 @@ mks_dmabuf_paintable_snapshot (GdkPaintable *paintable,
   /**
    * If the widget gets resized, snapshot would be called even
    * if we didn't receive a new DMABufUpdate call.
-   * So only create a new GLTexture when that happens
+   * So only create a new DmabufTexture when that happens
    */
   if (self->dmabuf_updated)
     {
-      texture_id = gdk_gl_texture_builder_get_id (self->builder);
-      gl_context = gdk_gl_texture_builder_get_context (self->builder);
 
-
-      gdk_gl_texture_builder_set_update_texture (self->builder, self->texture);
-      texture = gdk_gl_texture_builder_build (self->builder,
-                                              mks_dmabuf_texture_data_free,
-                                              mks_dmabuf_texture_data_new (gl_context, 
-                                                                           texture_id));
+      gdk_dmabuf_texture_builder_set_update_texture (self->builder, self->texture);
+      texture = gdk_dmabuf_texture_builder_build (self->builder,
+                                                  NULL, NULL, &error);
+      if (error != NULL)
+        {
+          g_warning ("Failed to build texture: %s", error->message);
+          return;
+        }
+      g_assert (texture != NULL);
       // Clear up the update region to not union it with the next UpdateDMABuf call
-      gdk_gl_texture_builder_set_update_region (self->builder, NULL);
+      gdk_dmabuf_texture_builder_set_update_region (self->builder, NULL);
       g_set_object (&self->texture, texture);
       self->dmabuf_updated = FALSE;
     }
@@ -183,18 +146,16 @@ mks_dmabuf_paintable_init (MksDmabufPaintable *self)
 
 gboolean
 mks_dmabuf_paintable_import (MksDmabufPaintable   *self,
-                             GdkGLContext         *gl_context,
+                             GdkDisplay           *display,
                              MksDmabufScanoutData *data,
                              cairo_region_t       *region,
                              GError              **error)
 {
   cairo_region_t *accumulated_damages;
   cairo_region_t *previous_region;
-  GLuint texture_id;
-  guint zero = 0;
+  guint plane = 0;
 
   g_return_val_if_fail (MKS_IS_DMABUF_PAINTABLE (self), FALSE);
-  g_return_val_if_fail (!gl_context || GDK_IS_GL_CONTEXT (gl_context), FALSE);
 
   if (data->dmabuf_fd < 0)
     {
@@ -223,18 +184,6 @@ mks_dmabuf_paintable_import (MksDmabufPaintable   *self,
       gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
     }
 
-  if (!(texture_id = mks_gl_context_import_dmabuf (gl_context,
-                                                   data->fourcc, data->width, data->height,
-                                                   1, &data->dmabuf_fd, &data->stride, &zero,
-                                                   &data->modifier)))
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_FAILED,
-                   "Failed to import dmabuf into GL texture");
-      return FALSE;
-    }
-
   accumulated_damages = cairo_region_create ();
 
   if (region != NULL)
@@ -242,22 +191,27 @@ mks_dmabuf_paintable_import (MksDmabufPaintable   *self,
 
   if (self->builder != NULL)
     {
-      previous_region = gdk_gl_texture_builder_get_update_region (self->builder);
+      previous_region = gdk_dmabuf_texture_builder_get_update_region (self->builder);
       if (previous_region != NULL)
         cairo_region_union (accumulated_damages, previous_region);
     }
 
   g_clear_object (&self->builder);
 
-  self->builder = gdk_gl_texture_builder_new ();
-  gdk_gl_texture_builder_set_width (self->builder, self->width);
-  gdk_gl_texture_builder_set_height (self->builder, self->height);
-  gdk_gl_texture_builder_set_context (self->builder, gl_context);
-  gdk_gl_texture_builder_set_id (self->builder, texture_id);
+  self->builder = gdk_dmabuf_texture_builder_new ();
+  gdk_dmabuf_texture_builder_set_modifier (self->builder, data->modifier);
+  gdk_dmabuf_texture_builder_set_stride (self->builder, plane, data->stride);
+  gdk_dmabuf_texture_builder_set_fourcc (self->builder, data->fourcc);
+  gdk_dmabuf_texture_builder_set_width (self->builder, data->width);
+  gdk_dmabuf_texture_builder_set_height (self->builder, data->height);
+  gdk_dmabuf_texture_builder_set_fd (self->builder, plane, data->dmabuf_fd);
+  gdk_dmabuf_texture_builder_set_offset (self->builder, plane, 0);
+  gdk_dmabuf_texture_builder_set_display (self->builder, display);
+  gdk_dmabuf_texture_builder_set_n_planes (self->builder, 1);
 
   if (cairo_region_num_rectangles (accumulated_damages) > 0)
-    gdk_gl_texture_builder_set_update_region (self->builder,
-                                              accumulated_damages);
+    gdk_dmabuf_texture_builder_set_update_region (self->builder,
+                                                  accumulated_damages);
 
   g_clear_pointer (&accumulated_damages, cairo_region_destroy);
   self->dmabuf_updated = TRUE;
diff --git a/lib/mks-gl-context-private.h b/lib/mks-gl-context-private.h
deleted file mode 100644
index b5e0d17..0000000
--- a/lib/mks-gl-context-private.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * mks-gl-context-private.h
- *
- * Copyright 2023 Christian Hergert <chergert@redhat.com>
- *
- * 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.1 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 General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#pragma once
-
-#include <epoxy/egl.h>
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-GLuint mks_gl_context_import_dmabuf (GdkGLContext  *context,
-                                     guint32        format,
-                                     guint          width,
-                                     guint          height,
-                                     guint32        n_planes,
-                                     const int     *fds,
-                                     const guint32 *strides,
-                                     const guint32 *offsets,
-                                     const guint64 *modifiers);
-
-G_END_DECLS
diff --git a/lib/mks-gl-context.c b/lib/mks-gl-context.c
deleted file mode 100644
index 2aa1c62..0000000
--- a/lib/mks-gl-context.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * mks-gl-context.c
- *
- * Copyright 2023 Christian Hergert <chergert@redhat.com>
- *
- * 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.1 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 General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#include "config.h"
-
-#include <gdk/gdk.h>
-
-#ifdef GDK_WINDOWING_WAYLAND
-# include <gdk/wayland/gdkwayland.h>
-#endif
-
-#ifdef GDK_WINDOWING_X11
-# include <gdk/x11/gdkx.h>
-#endif
-
-#include "mks-gl-context-private.h"
-
-GLuint
-mks_gl_context_import_dmabuf (GdkGLContext  *context,
-                              guint32        format,
-                              guint          width,
-                              guint          height,
-                              guint32        n_planes,
-                              const int     *fds,
-                              const guint32 *strides,
-                              const guint32 *offsets,
-                              const guint64 *modifiers)
-{
-  GdkDisplay *display;
-  EGLDisplay egl_display;
-  EGLint attribs[2 * (3 + 4 * 5) + 1];
-  EGLImage image;
-  guint texture_id;
-  int i;
-
-  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), 0);
-  g_return_val_if_fail (0 < n_planes && n_planes <= 4, 0);
-
-  display = gdk_gl_context_get_display (context);
-
-#ifdef GDK_WINDOWING_WAYLAND
-  if (GDK_IS_WAYLAND_DISPLAY (display))
-    egl_display = gdk_wayland_display_get_egl_display (display);
-  else
-#endif
-#ifdef GDK_WINDOWING_X11
-  if (GDK_IS_X11_DISPLAY (display))
-    egl_display = gdk_x11_display_get_egl_display (display);
-  else
-#endif
-    egl_display = NULL;
-
-  if (egl_display == NULL)
-    {
-      g_warning ("Can't import dmabufs when not using EGL");
-      return 0;
-    }
-
-  i = 0;
-  attribs[i++] = EGL_WIDTH;
-  attribs[i++] = width;
-  attribs[i++] = EGL_HEIGHT;
-  attribs[i++] = height;
-  attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
-  attribs[i++] = format;
-
-  if (n_planes > 0)
-    {
-      attribs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
-      attribs[i++] = fds[0];
-      attribs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
-      attribs[i++] = offsets[0];
-      attribs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
-      attribs[i++] = strides[0];
-      if (modifiers)
-        {
-          attribs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
-          attribs[i++] = modifiers[0] & 0xFFFFFFFF;
-          attribs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
-          attribs[i++] = modifiers[0] >> 32;
-        }
-    }
-
-  if (n_planes > 1)
-    {
-      attribs[i++] = EGL_DMA_BUF_PLANE1_FD_EXT;
-      attribs[i++] = fds[1];
-      attribs[i++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
-      attribs[i++] = offsets[1];
-      attribs[i++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
-      attribs[i++] = strides[1];
-      if (modifiers)
-        {
-          attribs[i++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
-          attribs[i++] = modifiers[1] & 0xFFFFFFFF;
-          attribs[i++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
-          attribs[i++] = modifiers[1] >> 32;
-        }
-    }
-
-  if (n_planes > 2)
-    {
-      attribs[i++] = EGL_DMA_BUF_PLANE2_FD_EXT;
-      attribs[i++] = fds[2];
-      attribs[i++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
-      attribs[i++] = offsets[2];
-      attribs[i++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
-      attribs[i++] = strides[2];
-      if (modifiers)
-        {
-          attribs[i++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
-          attribs[i++] = modifiers[2] & 0xFFFFFFFF;
-          attribs[i++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
-          attribs[i++] = modifiers[2] >> 32;
-        }
-    }
-  if (n_planes > 3)
-    {
-      attribs[i++] = EGL_DMA_BUF_PLANE3_FD_EXT;
-      attribs[i++] = fds[3];
-      attribs[i++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
-      attribs[i++] = offsets[3];
-      attribs[i++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
-      attribs[i++] = strides[3];
-      if (modifiers)
-        {
-          attribs[i++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
-          attribs[i++] = modifiers[3] & 0xFFFFFFFF;
-          attribs[i++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
-          attribs[i++] = modifiers[3] >> 32;
-        }
-    }
-
-  attribs[i++] = EGL_NONE;
-
-  image = eglCreateImageKHR (egl_display,
-                             EGL_NO_CONTEXT,
-                             EGL_LINUX_DMA_BUF_EXT,
-                             (EGLClientBuffer)NULL,
-                             attribs);
-  if (image == EGL_NO_IMAGE)
-    {
-      g_warning ("Failed to create EGL image: %d\n", eglGetError ());
-      return 0;
-    }
-
-  gdk_gl_context_make_current (context);
-
-  glGenTextures (1, &texture_id);
-  glBindTexture (GL_TEXTURE_2D, texture_id);
-  glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, image);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-  eglDestroyImageKHR (egl_display, image);
-
-  return texture_id;
-}
diff --git a/lib/mks-paintable-private.h b/lib/mks-paintable-private.h
index 8deaf68..a64cbae 100644
--- a/lib/mks-paintable-private.h
+++ b/lib/mks-paintable-private.h
@@ -29,7 +29,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (MksPaintable, mks_paintable, MKS, PAINTABLE, GObject)
 
-GdkPaintable *_mks_paintable_new          (GCancellable  *cancellable,
+GdkPaintable *_mks_paintable_new          (GdkDisplay    *display,
+                                           GCancellable  *cancellable,
                                            int           *peer_fd,
                                            GError       **error);
 GdkCursor    *_mks_paintable_get_cursor   (MksPaintable  *self);
diff --git a/lib/mks-paintable.c b/lib/mks-paintable.c
index 0ac25b2..42b2f71 100644
--- a/lib/mks-paintable.c
+++ b/lib/mks-paintable.c
@@ -39,9 +39,9 @@
 struct _MksPaintable
 {
   GObject               parent_instance;
-  GdkGLContext         *gl_context;
   MksQemuListener      *listener;
   GDBusConnection      *connection;
+  GdkDisplay           *display;
   GdkPaintable         *child;
   GdkCursor            *cursor;
   MksDmabufScanoutData *scanout_data;
@@ -155,23 +155,6 @@ paintable_iface_init (GdkPaintableInterface *iface)
 G_DEFINE_FINAL_TYPE_WITH_CODE (MksPaintable, mks_paintable, G_TYPE_OBJECT,
                                G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, paintable_iface_init))
 
-static GdkGLContext *
-mks_paintable_get_gl_context (MksPaintable  *self,
-                              GError       **error)
-{
-  g_assert (MKS_IS_PAINTABLE (self));
-
-  if (self->gl_context == NULL)
-    {
-      GdkDisplay *display = gdk_display_get_default ();
-
-      if (!(self->gl_context = gdk_display_create_gl_context (display, error)))
-        return NULL;
-    }
-
-  return self->gl_context;
-}
-
 static void
 mks_paintable_dispose (GObject *object)
 {
@@ -180,8 +163,8 @@ mks_paintable_dispose (GObject *object)
   g_clear_object (&self->connection);
   g_clear_object (&self->listener);
   g_clear_object (&self->child);
-  g_clear_object (&self->gl_context);
   g_clear_object (&self->cursor);
+  g_clear_object (&self->display);
 
   G_OBJECT_CLASS (mks_paintable_parent_class)->dispose (object);
 }
@@ -396,7 +379,6 @@ mks_paintable_listener_update_dmabuf (MksPaintable          *self,
 {
   cairo_region_t *region = NULL;
   g_autoptr(GError) error = NULL;
-  GdkGLContext *gl_context;
 
   g_assert (MKS_IS_PAINTABLE (self));
   g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
@@ -409,9 +391,8 @@ mks_paintable_listener_update_dmabuf (MksPaintable          *self,
         y = self->scanout_data->height - y - height;
 
       region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { x, y, width, height });
-      if (!(gl_context = mks_paintable_get_gl_context (self, &error)) ||
-          !mks_dmabuf_paintable_import (MKS_DMABUF_PAINTABLE (self->child),
-                                        gl_context,
+      if (!mks_dmabuf_paintable_import (MKS_DMABUF_PAINTABLE (self->child),
+                                        self->display,
                                         self->scanout_data,
                                         region,
                                         &error))
@@ -705,7 +686,8 @@ mks_paintable_connection_cb (GObject      *object,
 }
 
 GdkPaintable *
-_mks_paintable_new (GCancellable  *cancellable,
+_mks_paintable_new (GdkDisplay    *display,
+                    GCancellable  *cancellable,
                     int           *peer_fd,
                     GError       **error)
 {
@@ -721,7 +703,7 @@ _mks_paintable_new (GCancellable  *cancellable,
   *peer_fd = -1;
 
   self = g_object_new (MKS_TYPE_PAINTABLE, NULL);
-
+  self->display = g_object_ref (display);
   /* Create a socketpair() to use for D-Bus P2P protocol. We will be receiving
    * DMA-BUF FDs over this.
    */
diff --git a/lib/mks-screen.c b/lib/mks-screen.c
index e28ca16..bc8db2b 100644
--- a/lib/mks-screen.c
+++ b/lib/mks-screen.c
@@ -25,6 +25,7 @@
 #include <sys/socket.h>
 
 #include <glib/gstdio.h>
+#include <gtk/gtk.h>
 
 #include "mks-device-private.h"
 #include "mks-enums.h"
@@ -637,6 +638,7 @@ mks_screen_attach_cb (GObject      *object,
  */
 void
 mks_screen_attach (MksScreen           *self,
+                   GdkDisplay          *display,
                    GCancellable        *cancellable,
                    GAsyncReadyCallback  callback,
                    gpointer             user_data)
@@ -654,7 +656,7 @@ mks_screen_attach (MksScreen           *self,
   g_task_set_source_tag (task, mks_screen_attach);
 
   if (!check_console (self, &error) ||
-      !(paintable = _mks_paintable_new (cancellable, &fd, &error)))
+      !(paintable = _mks_paintable_new (display, cancellable, &fd, &error)))
     goto failure;
 
   g_task_set_task_data (task, g_steal_pointer (&paintable), g_object_unref);
@@ -714,6 +716,7 @@ mks_screen_attach_finish (MksScreen     *self,
  */
 GdkPaintable *
 mks_screen_attach_sync (MksScreen     *self,
+                        GdkDisplay    *display,
                         GCancellable  *cancellable,
                         GError       **error)
 {
@@ -725,7 +728,7 @@ mks_screen_attach_sync (MksScreen     *self,
   g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
 
   if (!check_console (self, error) ||
-      !(paintable = _mks_paintable_new (cancellable, &fd, error)))
+      !(paintable = _mks_paintable_new (display, cancellable, &fd, error)))
     return NULL;
 
   unix_fd_list = g_unix_fd_list_new_from_array (&fd, 1), fd = -1;
diff --git a/lib/mks-screen.h b/lib/mks-screen.h
index 1215559..45aca39 100644
--- a/lib/mks-screen.h
+++ b/lib/mks-screen.h
@@ -91,6 +91,7 @@ gboolean       mks_screen_configure_sync     (MksScreen            *self,
                                               GError              **error);
 MKS_AVAILABLE_IN_ALL
 void           mks_screen_attach             (MksScreen            *self,
+                                              GdkDisplay           *display,
                                               GCancellable         *cancellable,
                                               GAsyncReadyCallback   callback,
                                               gpointer              user_data);
@@ -100,6 +101,7 @@ GdkPaintable  *mks_screen_attach_finish      (MksScreen            *self,
                                               GError              **error);
 MKS_AVAILABLE_IN_ALL
 GdkPaintable  *mks_screen_attach_sync        (MksScreen            *self,
+                                              GdkDisplay           *display,
                                               GCancellable         *cancellable,
                                               GError              **error);
 
diff --git a/meson.build b/meson.build
index f5d063e..6409d41 100644
--- a/meson.build
+++ b/meson.build
@@ -23,7 +23,7 @@ add_project_arguments(['-I' + meson.project_build_root()], language: 'c')
 
 # Check dependencies
 glib_req_version = '2.75.0'
-gtk_req_version = '4.11'
+gtk_req_version = '4.13'
 
 glib_req = '>= @0@'.format(glib_req_version)
 gtk_req = '>= @0@'.format(gtk_req_version)
@@ -40,7 +40,6 @@ if gtk_minor % 2 == 1
   gtk_minor = gtk_minor + 1
 endif
 
-libepoxy_dep = dependency('epoxy')
 libgio_dep = dependency('gio-2.0', version: glib_req)
 libgiounix_dep = dependency('gio-unix-2.0', version: glib_req)
 libgtk_dep = dependency('gtk4', version: gtk_req, fallback: ['gtk'])

From e1dc14b1d8c919a765442f43adb195f0514c4756 Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@redhat.com>
Date: Tue, 14 Nov 2023 14:13:54 +0100
Subject: [PATCH 2/3] Add a GtkGrphicsOffload for dmabuf passthrough

---
 lib/mks-display.c | 25 +++++++------------------
 1 file changed, 7 insertions(+), 18 deletions(-)

diff --git a/lib/mks-display.c b/lib/mks-display.c
index 3094ba7..e33108f 100644
--- a/lib/mks-display.c
+++ b/lib/mks-display.c
@@ -43,6 +43,7 @@ typedef struct
   MksScreenResizer   *resizer;
   MksDisplayPicture  *picture;
   MksInhibitor       *inhibitor;
+  GtkWidget          *offload;
   GtkShortcutTrigger *ungrab_trigger;
   guint               auto_resize : 1;
 } MksDisplayPrivate;
@@ -237,25 +238,12 @@ mks_display_dispose (GObject *object)
 
   mks_display_disconnect (self);
 
-  g_clear_pointer ((GtkWidget **)&priv->picture, gtk_widget_unparent);
+  g_clear_pointer (&priv->offload, gtk_widget_unparent);
   g_clear_object (&priv->resizer);
 
   G_OBJECT_CLASS (mks_display_parent_class)->dispose (object);
 }
 
-static void
-mks_display_snapshot (GtkWidget   *widget,
-                      GtkSnapshot *snapshot)
-{
-  MksDisplay *self = (MksDisplay *)widget;
-  MksDisplayPrivate *priv = mks_display_get_instance_private (self);
-
-  g_assert (MKS_IS_DISPLAY (self));
-  g_assert (GTK_IS_SNAPSHOT (snapshot));
-
-  gtk_widget_snapshot_child (widget, GTK_WIDGET (priv->picture), snapshot);
-}
-
 static gboolean
 mks_display_grab_focus (GtkWidget *widget)
 {
@@ -286,7 +274,7 @@ mks_display_measure (GtkWidget      *widget,
 
   g_assert (MKS_IS_DISPLAY (self));
 
-  gtk_widget_measure (GTK_WIDGET (priv->picture), orientation, for_size,
+  gtk_widget_measure (priv->offload, orientation, for_size,
                       minimum, natural, minimum_baseline, natural_baseline);
 }
 
@@ -318,7 +306,7 @@ mks_display_size_allocate (GtkWidget *widget,
       mks_screen_attributes_free (attributes);
     }
 
-  gtk_widget_size_allocate (GTK_WIDGET (priv->picture),
+  gtk_widget_size_allocate (priv->offload,
                             &(GtkAllocation) {
                               area.origin.x,
                               area.origin.y,
@@ -395,7 +383,6 @@ mks_display_class_init (MksDisplayClass *klass)
   widget_class->get_request_mode = mks_display_get_request_mode;
   widget_class->measure = mks_display_measure;
   widget_class->size_allocate = mks_display_size_allocate;
-  widget_class->snapshot = mks_display_snapshot;
   widget_class->grab_focus = mks_display_grab_focus;
 
   properties[PROP_SCREEN] =
@@ -428,7 +415,9 @@ mks_display_init (MksDisplay *self)
 
   priv->picture = g_object_new (MKS_TYPE_DISPLAY_PICTURE, NULL);
   priv->resizer = mks_screen_resizer_new ();
-  gtk_widget_set_parent (GTK_WIDGET (priv->picture), GTK_WIDGET (self));
+
+  priv->offload = gtk_graphics_offload_new (GTK_WIDGET (priv->picture));
+  gtk_widget_set_parent (priv->offload, GTK_WIDGET (self));
 
   controller = gtk_event_controller_legacy_new ();
   gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);

From 6e14423850876a2a61facbb22e094e3cc098e0ae Mon Sep 17 00:00:00 2001
From: Bilal Elmoussaoui <belmouss@redhat.com>
Date: Sun, 14 Jan 2024 15:54:13 +0100
Subject: [PATCH 3/3] ci: Add missing dependencies

Needed for gdbus-codegen & coverage job
---
 .gitlab-ci.yml | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 790c201..72aeddc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -13,9 +13,9 @@ tests:
   variables:
     MESON_FLAGS: "-Db_coverage=true -Ddocs=false -Dvapi=false -Dintrospection=disabled"
   before_script:
-    - sudo dnf install -y git gtk4-devel meson gcc lcov wget
+    - sudo dnf install -y git gtk4-devel meson gcc gcovr lcov wget
       qemu-system-x86 qemu-ui-dbus qemu-ui-opengl
-      dbus-x11 xorg-x11-server-Xvfb
+      dbus-x11 xorg-x11-server-Xvfb python3-packaging
   script:
     - meson setup _build
     - meson configure ${MESON_FLAGS} _build
@@ -24,7 +24,6 @@ tests:
     - cd tests
     - BUILDDIR=_build dbus-run-session xvfb-run -ad ./functional.sh
     - cd ..
-    - rm -rf _build/subprojects
     - ninja coverage-html -C _build
   artifacts:
     paths:
@@ -47,7 +46,7 @@ reference:
     MESON_FLAGS: "--buildtype=release -Ddocs=true -Dintrospection=enabled"
   before_script:
     - sudo dnf install -y git gtk4-devel meson gcc
-      gi-docgen gobject-introspection-devel vala
+      gi-docgen gobject-introspection-devel vala python3-packaging
   script:
     - mkdir -p pfx/
     - meson ${MESON_FLAGS} --prefix=${PWD}/pfx -Ddocs=true _build