[gtk+/wip/gdk-gl2: 8/13] wayland: Add OpenGL support



commit 8bc17f1e5e3f4c0d3531245786a2a9f1bedce602
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Oct 9 11:06:48 2014 +0200

    wayland: Add OpenGL support
    
    This uses EGL to implement GdkGLContext for wayland.

 configure.ac                       |    2 +-
 gdk/wayland/Makefile.am            |    5 +-
 gdk/wayland/gdkdisplay-wayland.c   |    4 +
 gdk/wayland/gdkdisplay-wayland.h   |   13 ++
 gdk/wayland/gdkglcontext-wayland.c |  414 ++++++++++++++++++++++++++++++++++++
 gdk/wayland/gdkglcontext-wayland.h |   63 ++++++
 gdk/wayland/gdkprivate-wayland.h   |    2 +
 gdk/wayland/gdkwayland.h           |    1 +
 gdk/wayland/gdkwaylandglcontext.h  |   45 ++++
 gdk/wayland/gdkwindow-wayland.c    |   85 +++++++-
 10 files changed, 624 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d8a87e2..560fab1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -427,7 +427,7 @@ fi
 
 PKG_PROG_PKG_CONFIG
 
-WAYLAND_DEPENDENCIES="wayland-client >= wayland_required_version xkbcommon >= 0.2.0 wayland-cursor >= 
wayland_required_version"
+WAYLAND_DEPENDENCIES="wayland-client >= wayland_required_version xkbcommon >= 0.2.0 wayland-cursor >= 
wayland_required_version  wayland-egl >= wayland_required_version"
 if test "$enable_wayland_backend" = "maybe" ; then
   AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
   PKG_CHECK_EXISTS($WAYLAND_DEPENDENCIES, [have_wayland_deps=yes], [have_wayland_deps=no])
diff --git a/gdk/wayland/Makefile.am b/gdk/wayland/Makefile.am
index 356fd28..1a779f0 100644
--- a/gdk/wayland/Makefile.am
+++ b/gdk/wayland/Makefile.am
@@ -39,7 +39,9 @@ libgdk_wayland_la_SOURCES =                   \
        gdkdisplay-wayland.h                    \
        gdkdnd-wayland.c                        \
        gdkeventsource.c                        \
-       gdkkeys-wayland.c                       \
+       gdkkeys-wayland.c                       \
+       gdkglcontext-wayland.c                  \
+       gdkglcontext-wayland.h                  \
        gdkscreen-wayland.c                     \
        gdkselection-wayland.c                  \
        gdkwindow-wayland.c                     \
@@ -54,6 +56,7 @@ libgdkinclude_HEADERS =                               \
 libgdkwaylandinclude_HEADERS =                         \
        gdkwaylanddevice.h                      \
        gdkwaylanddisplay.h                     \
+       gdkwaylandglcontext.h                   \
        gdkwaylandselection.h                   \
        gdkwaylandwindow.h
 
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index dc344b4..5b6fc92 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -34,6 +34,7 @@
 #include "gdkdevicemanager.h"
 #include "gdkkeysprivate.h"
 #include "gdkprivate-wayland.h"
+#include "gdkglcontext-wayland.h"
 
 /**
  * SECTION:wayland_interaction
@@ -540,6 +541,9 @@ gdk_wayland_display_class_init (GdkWaylandDisplayClass * class)
   display_class->convert_selection = _gdk_wayland_display_convert_selection;
   display_class->text_property_to_utf8_list = _gdk_wayland_display_text_property_to_utf8_list;
   display_class->utf8_to_string_target = _gdk_wayland_display_utf8_to_string_target;
+
+  display_class->destroy_gl_context = gdk_wayland_display_destroy_gl_context;
+  display_class->make_gl_context_current = gdk_wayland_display_make_gl_context_current;
 }
 
 static void
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index 18f38df..daa8baf 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -26,6 +26,7 @@
 #include <stdint.h>
 #include <wayland-client.h>
 #include <wayland-cursor.h>
+#include <wayland-egl.h>
 #include <gdk/wayland/gtk-shell-client-protocol.h>
 #include <gdk/wayland/xdg-shell-client-protocol.h>
 
@@ -37,6 +38,8 @@
 
 #include "gdkdisplayprivate.h"
 
+#include <epoxy/egl.h>
+
 G_BEGIN_DECLS
 
 typedef struct _GdkWaylandSelection GdkWaylandSelection;
@@ -76,6 +79,16 @@ struct _GdkWaylandDisplay
   struct xkb_context *xkb_context;
 
   GdkWaylandSelection *selection;
+
+  /* egl info */
+  EGLDisplay egl_display;
+  int egl_major_version;
+  int egl_minor_version;
+
+  guint have_egl : 1;
+  guint have_egl_khr_create_context : 1;
+  guint have_egl_buffer_age : 1;
+  guint have_egl_swap_buffers_with_damage : 1;
 };
 
 struct _GdkWaylandDisplayClass
diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c
new file mode 100644
index 0000000..5ddcdcd
--- /dev/null
+++ b/gdk/wayland/gdkglcontext-wayland.c
@@ -0,0 +1,414 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-wayland.c: Wayland specific OpenGL wrappers
+ *
+ * Copyright © 2014  Emmanuele Bassi
+ * Copyright © 2014  Alexander Larsson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkglcontext-wayland.h"
+#include "gdkdisplay-wayland.h"
+
+#include "gdkwaylanddisplay.h"
+#include "gdkwaylandglcontext.h"
+#include "gdkwaylandwindow.h"
+#include "gdkprivate-wayland.h"
+
+#include "gdkinternals.h"
+
+#include "gdkintl.h"
+
+G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT)
+
+static void
+gdk_wayland_gl_context_update (GdkGLContext *context)
+{
+  GdkWindow *window = gdk_gl_context_get_window (context);
+  int width, height;
+
+  if (!gdk_gl_context_make_current (context))
+    return;
+
+  width = gdk_window_get_width (window);
+  height = gdk_window_get_height (window);
+
+  GDK_NOTE (OPENGL, g_print ("Updating GL viewport size to { %d, %d } for window %p (context: %p)\n",
+                             width, height,
+                             window, context));
+
+  glViewport (0, 0, width, height);
+}
+
+void
+gdk_wayland_window_invalidate_for_new_frame (GdkWindow      *window,
+                                             cairo_region_t *update_area)
+{
+  cairo_rectangle_int_t window_rect;
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkWaylandGLContext *context_wayland;
+  int buffer_age;
+  gboolean invalidate_all;
+  EGLSurface egl_surface;
+
+  /* Minimal update is ok if we're not drawing with gl */
+  if (window->gl_paint_context == NULL)
+    return;
+
+  context_wayland = GDK_WAYLAND_GL_CONTEXT (window->gl_paint_context);
+  buffer_age = 0;
+
+  egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window,
+                                                    context_wayland->egl_config);
+
+  if (display_wayland->have_egl_buffer_age)
+    eglQuerySurface (display_wayland->egl_display, egl_surface,
+                     EGL_BUFFER_AGE_EXT, &buffer_age);
+
+  invalidate_all = FALSE;
+  if (buffer_age == 0 || buffer_age >= 4)
+    invalidate_all = TRUE;
+  else
+    {
+      if (buffer_age >= 2)
+        {
+          if (window->old_updated_area[0])
+            cairo_region_union (update_area, window->old_updated_area[0]);
+          else
+            invalidate_all = TRUE;
+        }
+      if (buffer_age >= 3)
+        {
+          if (window->old_updated_area[1])
+            cairo_region_union (update_area, window->old_updated_area[1]);
+          else
+            invalidate_all = TRUE;
+        }
+    }
+
+  if (invalidate_all)
+    {
+      window_rect.x = 0;
+      window_rect.y = 0;
+      window_rect.width = gdk_window_get_width (window);
+      window_rect.height = gdk_window_get_height (window);
+
+      /* If nothing else is known, repaint everything so that the back
+         buffer is fully up-to-date for the swapbuffer */
+      cairo_region_union_rectangle (update_area, &window_rect);
+    }
+}
+
+static void
+gdk_wayland_gl_context_flush_buffer (GdkGLContext *context,
+                                     cairo_region_t *painted,
+                                     cairo_region_t *damage)
+{
+  GdkWindow *window = gdk_gl_context_get_window (context);
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
+  EGLSurface egl_surface;
+
+  if (!gdk_gl_context_make_current (context))
+    return;
+
+  egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window,
+                                                    context_wayland->egl_config);
+
+  // TODO: Use eglSwapBuffersWithDamageEXT if available
+  if (display_wayland->have_egl_swap_buffers_with_damage)
+    {
+      int i, j, n_rects = cairo_region_num_rectangles (damage);
+      EGLint *rects = g_new (EGLint, n_rects * 4);
+      cairo_rectangle_int_t rect;
+      int window_height = gdk_window_get_height (window);
+
+      for (i = 0, j = 0; i < n_rects; i++)
+        {
+          cairo_region_get_rectangle (damage, i, &rect);
+          rects[j++] = rect.x;
+          rects[j++] = window_height - rect.height - rect.y;
+          rects[j++] = rect.width;
+          rects[j++] = rect.height;
+        }
+      eglSwapBuffersWithDamageEXT (display_wayland->egl_display, egl_surface, rects, n_rects);
+      g_free (rects);
+    }
+  else
+    eglSwapBuffers (display_wayland->egl_display, egl_surface);
+}
+
+static void
+gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
+{
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+
+  context_class->update = gdk_wayland_gl_context_update;
+  context_class->flush_buffer = gdk_wayland_gl_context_flush_buffer;
+}
+
+static void
+gdk_wayland_gl_context_init (GdkWaylandGLContext *self)
+{
+}
+
+gboolean
+gdk_wayland_display_init_gl (GdkDisplay *display)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  EGLint major, minor;
+  EGLDisplay *dpy;
+
+  if (display_wayland->have_egl)
+    return TRUE;
+
+  dpy = eglGetDisplay ((EGLNativeDisplayType)display_wayland->wl_display);
+  if (dpy == NULL)
+    return FALSE;
+
+  if (!eglInitialize (dpy, &major, &minor))
+    return FALSE;
+
+  if (!eglBindAPI (EGL_OPENGL_API))
+    return FALSE;
+
+  display_wayland->egl_display = dpy;
+  display_wayland->egl_major_version = major;
+  display_wayland->egl_minor_version = minor;
+
+  display_wayland->have_egl = TRUE;
+
+  display_wayland->have_egl_khr_create_context =
+    epoxy_has_egl_extension (dpy, "EGL_KHR_create_context");
+
+  display_wayland->have_egl_buffer_age =
+    epoxy_has_egl_extension (dpy, "EGL_EXT_buffer_age");
+
+  display_wayland->have_egl_swap_buffers_with_damage =
+    epoxy_has_egl_extension (dpy, "EGL_EXT_swap_buffers_with_damage");
+
+  GDK_NOTE (OPENGL,
+            g_print ("EGL API version %d.%d found\n"
+                     " - Vendor: %s\n"
+                     " - Version: %s\n"
+                     " - Client APIs: %s\n"
+                     " - Extensions:\n"
+                     "\t%s\n"
+                     ,
+                     display_wayland->egl_major_version,
+                     display_wayland->egl_minor_version,
+                     eglQueryString (dpy, EGL_VENDOR),
+                     eglQueryString(dpy, EGL_VERSION),
+                     eglQueryString(dpy, EGL_CLIENT_APIS),
+                     eglQueryString(dpy, EGL_EXTENSIONS)));
+
+  return TRUE;
+}
+
+#define MAX_EGL_ATTRS   30
+
+static gboolean
+find_eglconfig_for_window (GdkWindow        *window,
+                           EGLConfig         *egl_config_out,
+                           GError           **error)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkVisual *visual = gdk_window_get_visual (window);
+  EGLint attrs[MAX_EGL_ATTRS];
+  EGLint count;
+  EGLConfig *configs;
+  gboolean use_rgba;
+
+  int i = 0;
+
+  attrs[i++] = EGL_SURFACE_TYPE;
+  attrs[i++] = EGL_WINDOW_BIT;
+
+  attrs[i++] = EGL_COLOR_BUFFER_TYPE;
+  attrs[i++] = EGL_RGB_BUFFER;
+
+  attrs[i++] = EGL_RED_SIZE;
+  attrs[i++] = gdk_visual_get_bits_per_rgb (visual);
+  attrs[i++] = EGL_GREEN_SIZE;
+  attrs[i++] = gdk_visual_get_bits_per_rgb (visual);
+  attrs[i++] = EGL_BLUE_SIZE;
+  attrs[i++] = gdk_visual_get_bits_per_rgb (visual);
+
+  use_rgba = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display)));
+
+  if (use_rgba)
+    {
+      attrs[i++] = EGL_ALPHA_SIZE;
+      attrs[i++] = 1;
+    }
+  else
+    {
+      attrs[i++] = EGL_ALPHA_SIZE;
+      attrs[i++] = 0;
+    }
+
+  attrs[i++] = EGL_NONE;
+  g_assert (i < MAX_EGL_ATTRS);
+
+  if (!eglChooseConfig (display_wayland->egl_display, attrs, NULL, 0, &count) || count < 1)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                           _("No available configurations for the given pixel format"));
+      return FALSE;
+    }
+
+  configs = g_new (EGLConfig, count);
+
+  if (!eglChooseConfig (display_wayland->egl_display, attrs, configs, count, &count) || count < 1)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                           _("No available configurations for the given pixel format"));
+      return FALSE;
+    }
+
+  /* Pick first valid configuration i guess? */
+
+  if (egl_config_out != NULL)
+    *egl_config_out = configs[0];
+
+  g_free (configs);
+
+  return TRUE;
+}
+
+GdkGLContext *
+gdk_wayland_window_create_gl_context (GdkWindow     *window,
+                                      GdkGLProfile   profile,
+                                      GdkGLContext  *share,
+                                      GError       **error)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkWaylandGLContext *context;
+  EGLContext ctx;
+  EGLConfig config;
+  int i;
+  EGLint context_attribs[3];
+
+  if (!gdk_wayland_display_init_gl (display))
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("No GL implementation is available"));
+      return NULL;
+    }
+
+  if (profile == GDK_GL_PROFILE_3_2_CORE &&
+      !display_wayland->have_egl_khr_create_context)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_PROFILE,
+                           _("3.2 core GL profile is not available on EGL implementation"));
+      return NULL;
+    }
+
+  if (!find_eglconfig_for_window (window, &config, error))
+    return NULL;
+
+  i = 0;
+  if (profile == GDK_GL_PROFILE_3_2_CORE)
+    {
+      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+      context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
+    }
+  context_attribs[i++] = EGL_NONE;
+
+  ctx = eglCreateContext (display_wayland->egl_display,
+                          config,
+                          share ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context : EGL_NO_CONTEXT,
+                          context_attribs);
+  if (ctx == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return NULL;
+    }
+
+  GDK_NOTE (OPENGL,
+            g_print ("Created EGL context[%p]\n", ctx));
+
+  context = g_object_new (GDK_WAYLAND_TYPE_GL_CONTEXT,
+                          "window", window,
+                          "visual", gdk_window_get_visual (window),
+                          NULL);
+
+  context->egl_config = config;
+  context->egl_context = ctx;
+
+  return GDK_GL_CONTEXT (context);
+}
+
+void
+gdk_wayland_display_destroy_gl_context (GdkDisplay   *display,
+                                        GdkGLContext *context)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
+
+  /* TODO: Unset as current if current? */
+  if (context_wayland->egl_context != NULL)
+    {
+      if (eglGetCurrentContext () == context_wayland->egl_context)
+        eglMakeCurrent(display_wayland->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                       EGL_NO_CONTEXT);
+
+      GDK_NOTE (OPENGL, g_print ("Destroying EGL context\n"));
+
+      eglDestroyContext (display_wayland->egl_display,
+                         context_wayland->egl_context);
+      context_wayland->egl_context = NULL;
+    }
+}
+
+gboolean
+gdk_wayland_display_make_gl_context_current (GdkDisplay   *display,
+                                             GdkGLContext *context)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkWaylandGLContext *context_wayland;
+  GdkWindow *window;
+  EGLSurface egl_surface;
+
+  if (context == NULL)
+    {
+      eglMakeCurrent(display_wayland->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                     EGL_NO_CONTEXT);
+      return TRUE;
+    }
+
+  context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
+  window = gdk_gl_context_get_window (context);
+
+  egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window, context_wayland->egl_config);
+
+  if (!eglMakeCurrent(display_wayland->egl_display, egl_surface,
+                      egl_surface, context_wayland->egl_context))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/gdk/wayland/gdkglcontext-wayland.h b/gdk/wayland/gdkglcontext-wayland.h
new file mode 100644
index 0000000..475a28b
--- /dev/null
+++ b/gdk/wayland/gdkglcontext-wayland.h
@@ -0,0 +1,63 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-wayland.h: Private Wayland specific OpenGL wrappers
+ *
+ * Copyright © 2014  Emmanuele Bassi
+ * Copyright © 2014  Red Hat, Int
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_WAYLAND_GL_CONTEXT__
+#define __GDK_WAYLAND_GL_CONTEXT__
+
+#include "gdkglcontextprivate.h"
+#include "gdkdisplayprivate.h"
+#include "gdkvisual.h"
+#include "gdkwindow.h"
+#include "gdkinternals.h"
+#include "gdkmain.h"
+
+#include <epoxy/egl.h>
+
+G_BEGIN_DECLS
+
+struct _GdkWaylandGLContext
+{
+  GdkGLContext parent_instance;
+
+  EGLContext egl_context;
+  EGLConfig egl_config;
+};
+
+struct _GdkWaylandGLContextClass
+{
+  GdkGLContextClass parent_class;
+};
+
+gboolean        gdk_wayland_display_init_gl                         (GdkDisplay        *display);
+GdkGLContext *  gdk_wayland_window_create_gl_context                (GdkWindow         *window,
+                                                                     GdkGLProfile       profile,
+                                                                     GdkGLContext      *share,
+                                                                     GError           **error);
+void            gdk_wayland_window_invalidate_for_new_frame         (GdkWindow         *window,
+                                                                     cairo_region_t    *update_area);
+void            gdk_wayland_display_destroy_gl_context              (GdkDisplay        *display,
+                                                                     GdkGLContext      *context);
+gboolean        gdk_wayland_display_make_gl_context_current         (GdkDisplay        *display,
+                                                                     GdkGLContext      *context);
+
+G_END_DECLS
+
+#endif /* __GDK_WAYLAND_GL_CONTEXT__ */
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index b1e6e14..b72b359 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -237,5 +237,7 @@ struct wl_data_source * gdk_wayland_selection_get_data_source (GdkWindow *owner,
                                                                GdkAtom    selection);
 void gdk_wayland_selection_unset_data_source (GdkAtom selection);
 
+EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
+                                               EGLConfig config);
 
 #endif /* __GDK_PRIVATE_WAYLAND_H__ */
diff --git a/gdk/wayland/gdkwayland.h b/gdk/wayland/gdkwayland.h
index 29a8cb3..39c887c 100644
--- a/gdk/wayland/gdkwayland.h
+++ b/gdk/wayland/gdkwayland.h
@@ -33,6 +33,7 @@
 #include <gdk/wayland/gdkwaylanddisplay.h>
 #include <gdk/wayland/gdkwaylandselection.h>
 #include <gdk/wayland/gdkwaylandwindow.h>
+#include <gdk/wayland/gdkwaylandglcontext.h>
 
 #undef __GDKWAYLAND_H_INSIDE__
 
diff --git a/gdk/wayland/gdkwaylandglcontext.h b/gdk/wayland/gdkwaylandglcontext.h
new file mode 100644
index 0000000..27b7e8f
--- /dev/null
+++ b/gdk/wayland/gdkwaylandglcontext.h
@@ -0,0 +1,45 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-wayland.c: Wayland specific OpenGL wrappers
+ *
+ * Copyright © 2014  Emmanuele Bassi
+ * Copyright © 2014  Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_WAYLAND_GL_CONTEXT_H__
+#define __GDK_WAYLAND_GL_CONTEXT_H__
+
+#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkwayland.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_WAYLAND_TYPE_GL_CONTEXT            (gdk_wayland_gl_context_get_type ())
+#define GDK_WAYLAND_GL_CONTEXT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GDK_WAYLAND_TYPE_GL_CONTEXT, GdkWaylandGLContext))
+#define GDK_WAYLAND_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_WAYLAND_TYPE_GL_CONTEXT))
+
+typedef struct _GdkWaylandGLContext            GdkWaylandGLContext;
+typedef struct _GdkWaylandGLContextClass       GdkWaylandGLContextClass;
+
+GDK_AVAILABLE_IN_3_14
+GType gdk_wayland_gl_context_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_WAYLAND_GL_CONTEXT_H__ */
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 5674259..90d75ef 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -26,6 +26,7 @@
 #include "gdkwindow.h"
 #include "gdkwindowimpl.h"
 #include "gdkdisplay-wayland.h"
+#include "gdkglcontext-wayland.h"
 #include "gdkframeclockprivate.h"
 #include "gdkprivate-wayland.h"
 #include "gdkinternals.h"
@@ -97,6 +98,9 @@ struct _GdkWindowImplWayland
 
   struct wl_subsurface *subsurface;
 
+  struct wl_egl_window *egl_window;
+  EGLSurface egl_surface;
+
   unsigned int mapped : 1;
   unsigned int use_custom_surface : 1;
   unsigned int pending_commit : 1;
@@ -170,6 +174,9 @@ gdk_wayland_window_update_size (GdkWindow *window,
   window->width = width;
   window->height = height;
 
+  if (impl->egl_window)
+    wl_egl_window_resize (impl->egl_window, width, height, 0, 0);
+
   area.x = 0;
   area.y = 0;
   area.width = window->width;
@@ -582,15 +589,18 @@ gdk_window_impl_wayland_end_paint (GdkWindow *window)
   cairo_rectangle_int_t rect;
   int i, n;
 
-  gdk_wayland_window_attach_image (window);
-
-  n = cairo_region_num_rectangles (window->current_paint.region);
-  for (i = 0; i < n; i++)
+  if (!window->current_paint.use_gl)
     {
-      cairo_region_get_rectangle (window->current_paint.region, i, &rect);
-      wl_surface_damage (impl->surface,
-                         rect.x, rect.y, rect.width, rect.height);
-      impl->pending_commit = TRUE;
+      gdk_wayland_window_attach_image (window);
+
+      n = cairo_region_num_rectangles (window->current_paint.region);
+      for (i = 0; i < n; i++)
+        {
+          cairo_region_get_rectangle (window->current_paint.region, i, &rect);
+          wl_surface_damage (impl->surface,
+                             rect.x, rect.y, rect.width, rect.height);
+          impl->pending_commit = TRUE;
+        }
     }
 }
 
@@ -1156,10 +1166,23 @@ gdk_wayland_window_show (GdkWindow *window,
 static void
 gdk_wayland_window_hide_surface (GdkWindow *window)
 {
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
   if (impl->surface)
     {
+      if (impl->egl_surface)
+        {
+          eglDestroySurface(display_wayland->egl_display, impl->egl_surface);
+          impl->egl_surface = NULL;
+        }
+
+      if (impl->egl_window)
+        {
+          wl_egl_window_destroy (impl->egl_window);
+          impl->egl_window = NULL;
+        }
+
       if (impl->xdg_surface)
         {
           xdg_surface_destroy (impl->xdg_surface);
@@ -2128,6 +2151,8 @@ _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass)
   impl_class->set_opaque_region = gdk_wayland_window_set_opaque_region;
   impl_class->set_shadow_width = gdk_wayland_window_set_shadow_width;
   impl_class->show_window_menu = gdk_wayland_window_show_window_menu;
+  impl_class->create_gl_context = gdk_wayland_window_create_gl_context;
+  impl_class->invalidate_for_new_frame = gdk_wayland_window_invalidate_for_new_frame;
 }
 
 void
@@ -2169,6 +2194,50 @@ gdk_wayland_window_get_wl_surface (GdkWindow *window)
   return impl->surface;
 }
 
+static struct wl_egl_window *
+gdk_wayland_window_get_wl_egl_window (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl;
+
+  g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  if (impl->egl_window == NULL)
+    {
+      impl->egl_window =
+        wl_egl_window_create(impl->surface,
+                             impl->wrapper->width,
+                             impl->wrapper->height);
+    }
+
+  return impl->egl_window;
+}
+
+EGLSurface
+gdk_wayland_window_get_egl_surface (GdkWindow *window,
+                                    EGLConfig config)
+{
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
+  GdkWindowImplWayland *impl;
+  struct wl_egl_window *egl_window;
+
+  g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  if (impl->egl_surface == NULL)
+    {
+      egl_window = gdk_wayland_window_get_wl_egl_window (window);
+
+      impl->egl_surface =
+        eglCreateWindowSurface (display_wayland->egl_display,
+                                config, egl_window, NULL);
+    }
+
+  return impl->egl_surface;
+}
+
 /**
  * gdk_wayland_window_set_use_custom_surface:
  * @window: (type GdkWaylandWindow): a #GdkWindow


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