summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Trevisan (Treviño) <mail@3v1n0.net>2014-11-18 22:23:52 +0100
committerMarco Trevisan (Treviño) <mail@3v1n0.net>2014-11-20 04:33:38 +0100
commit6e9db05601e33ccfc71bd55c17f114caffd6f93b (patch)
treea7254541eccf77b3c8bb3d5dbe6395aebc63e3ad
parent45cfb405c0e34c69ccc483455d31febca60abb33 (diff)
downloadgtk+-6e9db05601e33ccfc71bd55c17f114caffd6f93b.tar.gz
mir: add OpenGL support
Implement GdkGLContext using EGL and use hardware mir surfaces when a GdkWindow uses gl rendering. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=740346
-rw-r--r--gdk/mir/Makefile.am1
-rw-r--r--gdk/mir/gdkmir-private.h42
-rw-r--r--gdk/mir/gdkmir.h10
-rw-r--r--gdk/mir/gdkmirdisplay.c187
-rw-r--r--gdk/mir/gdkmirglcontext.c125
-rw-r--r--gdk/mir/gdkmirwindowimpl.c408
6 files changed, 705 insertions, 68 deletions
diff --git a/gdk/mir/Makefile.am b/gdk/mir/Makefile.am
index 026ce7981a..d71c377a09 100644
--- a/gdk/mir/Makefile.am
+++ b/gdk/mir/Makefile.am
@@ -24,6 +24,7 @@ libgdk_mir_la_SOURCES = \
gdkmirdevicemanager.c \
gdkmirdisplay.c \
gdkmireventsource.c \
+ gdkmirglcontext.c \
gdkmirkeyboard.c \
gdkmirkeymap.c \
gdkmirpointer.c \
diff --git a/gdk/mir/gdkmir-private.h b/gdk/mir/gdkmir-private.h
index 8305096241..053615a210 100644
--- a/gdk/mir/gdkmir-private.h
+++ b/gdk/mir/gdkmir-private.h
@@ -18,10 +18,13 @@
#ifndef __GDK_PRIVATE_MIR_H__
#define __GDK_PRIVATE_MIR_H__
+#include <epoxy/egl.h>
+
#include "gdkmir.h"
#include "gdkdisplay.h"
#include "gdkscreen.h"
#include "gdkdevicemanager.h"
+#include "gdkglcontextprivate.h"
#include "gdkkeys.h"
#include "gdkwindowimpl.h"
@@ -35,6 +38,27 @@ typedef struct _GdkMirEventSource GdkMirEventSource;
GType gdk_mir_window_impl_get_type (void);
+
+struct _GdkMirGLContext
+{
+ GdkGLContext parent_instance;
+
+ EGLContext egl_context;
+ EGLConfig egl_config;
+ gboolean is_attached;
+};
+
+struct _GdkMirGLContextClass
+{
+ GdkGLContextClass parent_class;
+};
+
+typedef struct _GdkMirGLContext GdkMirGLContext;
+typedef struct _GdkMirGLContextClass GdkMirGLContextClass;
+
+#define GDK_MIR_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_MIR_GL_CONTEXT, GdkMirGLContext))
+
+
GdkDisplay *_gdk_mir_display_open (const gchar *display_name);
GdkScreen *_gdk_mir_screen_new (GdkDisplay *display);
@@ -77,6 +101,24 @@ void _gdk_mir_window_reference_unref (GdkMirWindowReference *ref);
void _gdk_mir_event_source_queue (GdkMirWindowReference *window_ref, const MirEvent *event);
+MirPixelFormat _gdk_mir_display_get_pixel_format (GdkDisplay *display, MirBufferUsage usage);
+
+gboolean _gdk_mir_display_init_egl_display (GdkDisplay *display);
+
+EGLDisplay _gdk_mir_display_get_egl_display (GdkDisplay *display);
+
+gboolean _gdk_mir_display_have_egl_khr_create_context (GdkDisplay *display);
+
+gboolean _gdk_mir_display_have_egl_buffer_age (GdkDisplay *display);
+
+gboolean _gdk_mir_display_have_egl_swap_buffers_with_damage (GdkDisplay *display);
+
+gboolean _gdk_mir_display_have_egl_surfaceless_context (GdkDisplay *display);
+
+EGLSurface _gdk_mir_window_get_egl_surface (GdkWindow *window, EGLConfig config);
+
+EGLSurface _gdk_mir_window_get_dummy_egl_surface (GdkWindow *window, EGLConfig config);
+
void _gdk_mir_print_modifiers (unsigned int modifiers);
void _gdk_mir_print_key_event (const MirKeyEvent *event);
diff --git a/gdk/mir/gdkmir.h b/gdk/mir/gdkmir.h
index a1c15d1a12..48070dd1da 100644
--- a/gdk/mir/gdkmir.h
+++ b/gdk/mir/gdkmir.h
@@ -24,8 +24,11 @@
#define GDK_TYPE_MIR_DISPLAY (gdk_mir_display_get_type ())
#define GDK_IS_MIR_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_DISPLAY))
-#define GDK_TYPE_MIR_WINDOW (gdk_mir_window_get_type ())
-#define GDK_IS_WINDOW_MIR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_WINDOW))
+#define GDK_TYPE_MIR_GL_CONTEXT (gdk_mir_gl_context_get_type ())
+#define GDK_MIR_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_MIR_GL_CONTEXT))
+
+#define GDK_TYPE_MIR_WINDOW (gdk_mir_window_get_type ())
+#define GDK_IS_WINDOW_MIR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_WINDOW))
GDK_AVAILABLE_IN_3_10
GType gdk_mir_display_get_type (void);
@@ -36,4 +39,7 @@ struct MirConnection *gdk_mir_display_get_mir_connection (GdkDisplay *display);
GDK_AVAILABLE_IN_3_10
GType gdk_mir_window_get_type (void);
+GDK_AVAILABLE_IN_3_16
+GType gdk_mir_gl_context_get_type (void) G_GNUC_CONST;
+
#endif /* __GDK_MIR_H__ */
diff --git a/gdk/mir/gdkmirdisplay.c b/gdk/mir/gdkmirdisplay.c
index b44cc79789..dd71ac63ee 100644
--- a/gdk/mir/gdkmirdisplay.c
+++ b/gdk/mir/gdkmirdisplay.c
@@ -46,6 +46,15 @@ typedef struct GdkMirDisplay
GdkScreen *screen;
GdkKeymap *keymap;
+
+ MirPixelFormat sw_pixel_format;
+ MirPixelFormat hw_pixel_format;
+
+ EGLDisplay egl_display;
+ guint have_egl_khr_create_context : 1;
+ guint have_egl_buffer_age : 1;
+ guint have_egl_swap_buffers_with_damage : 1;
+ guint have_egl_surfaceless_context : 1;
} GdkMirDisplay;
typedef struct GdkMirDisplayClass
@@ -53,6 +62,8 @@ typedef struct GdkMirDisplayClass
GdkDisplayClass parent_class;
} GdkMirDisplayClass;
+static void initialize_pixel_formats (GdkMirDisplay *display);
+
/**
* SECTION:mir_interaction
* @Short_description: Mir backend-specific functions
@@ -112,6 +123,7 @@ _gdk_mir_display_open (const gchar *display_name)
display->connection = connection;
GDK_DISPLAY (display)->device_manager = _gdk_mir_device_manager_new (GDK_DISPLAY (display));
display->screen = _gdk_mir_screen_new (GDK_DISPLAY (display));
+ initialize_pixel_formats (display);
g_signal_emit_by_name (display, "opened");
@@ -488,6 +500,180 @@ gdk_mir_display_utf8_to_string_target (GdkDisplay *display,
}
static void
+initialize_pixel_formats (GdkMirDisplay *display)
+{
+ MirPixelFormat formats[mir_pixel_formats];
+ unsigned int n_formats, i;
+
+ mir_connection_get_available_surface_formats (display->connection, formats,
+ mir_pixel_formats, &n_formats);
+
+ display->sw_pixel_format = mir_pixel_format_invalid;
+ display->hw_pixel_format = mir_pixel_format_invalid;
+
+ for (i = 0; i < n_formats; i++)
+ {
+ switch (formats[i])
+ {
+ case mir_pixel_format_abgr_8888:
+ case mir_pixel_format_xbgr_8888:
+ case mir_pixel_format_argb_8888:
+ case mir_pixel_format_xrgb_8888:
+ display->hw_pixel_format = formats[i];
+ break;
+ default:
+ continue;
+ }
+
+ if (display->hw_pixel_format != mir_pixel_format_invalid)
+ break;
+ }
+
+ for (i = 0; i < n_formats; i++)
+ {
+ if (formats[i] == mir_pixel_format_argb_8888)
+ {
+ display->sw_pixel_format = formats[i];
+ break;
+ }
+ }
+}
+
+MirPixelFormat
+_gdk_mir_display_get_pixel_format (GdkDisplay *display,
+ MirBufferUsage usage)
+{
+ GdkMirDisplay *mir_dpy = GDK_MIR_DISPLAY (display);
+
+ if (usage == mir_buffer_usage_hardware)
+ return mir_dpy->hw_pixel_format;
+
+ return mir_dpy->sw_pixel_format;
+}
+
+gboolean
+_gdk_mir_display_init_egl_display (GdkDisplay *display)
+{
+ GdkMirDisplay *mir_dpy = GDK_MIR_DISPLAY (display);
+ EGLint major_version, minor_version;
+ EGLDisplay *dpy;
+
+ if (mir_dpy->egl_display)
+ return TRUE;
+
+ dpy = eglGetDisplay (mir_connection_get_egl_native_display (mir_dpy->connection));
+ if (dpy == NULL)
+ return FALSE;
+
+ if (!eglInitialize (dpy, &major_version, &minor_version))
+ return FALSE;
+
+ if (!eglBindAPI (EGL_OPENGL_API))
+ return FALSE;
+
+ mir_dpy->egl_display = dpy;
+
+ mir_dpy->have_egl_khr_create_context =
+ epoxy_has_egl_extension (dpy, "EGL_KHR_create_context");
+
+ mir_dpy->have_egl_buffer_age =
+ epoxy_has_egl_extension (dpy, "EGL_EXT_buffer_age");
+
+ mir_dpy->have_egl_swap_buffers_with_damage =
+ epoxy_has_egl_extension (dpy, "EGL_EXT_swap_buffers_with_damage");
+
+ mir_dpy->have_egl_surfaceless_context =
+ epoxy_has_egl_extension (dpy, "EGL_KHR_surfaceless_context");
+
+ 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",
+ major_version,
+ minor_version,
+ eglQueryString (dpy, EGL_VENDOR),
+ eglQueryString (dpy, EGL_VERSION),
+ eglQueryString (dpy, EGL_CLIENT_APIS),
+ eglQueryString (dpy, EGL_EXTENSIONS)));
+
+ return TRUE;
+}
+
+static gboolean
+gdk_mir_display_make_gl_context_current (GdkDisplay *display,
+ GdkGLContext *context)
+{
+ EGLDisplay egl_display = _gdk_mir_display_get_egl_display (display);
+ GdkMirGLContext *mir_context;
+ GdkWindow *window;
+ EGLSurface egl_surface;
+
+ if (context == NULL)
+ {
+ eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ return TRUE;
+ }
+
+ mir_context = GDK_MIR_GL_CONTEXT (context);
+ window = gdk_gl_context_get_window (context);
+
+ if (mir_context->is_attached)
+ {
+ egl_surface = _gdk_mir_window_get_egl_surface (window,
+ mir_context->egl_config);
+ }
+ else
+ {
+ if (_gdk_mir_display_have_egl_surfaceless_context (display))
+ egl_surface = EGL_NO_SURFACE;
+ else
+ egl_surface = _gdk_mir_window_get_dummy_egl_surface (window,
+ mir_context->egl_config);
+ }
+
+ if (!eglMakeCurrent (egl_display, egl_surface, egl_surface, mir_context->egl_context))
+ {
+ g_warning ("eglMakeCurrent failed");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+EGLDisplay _gdk_mir_display_get_egl_display (GdkDisplay *display)
+{
+ return GDK_MIR_DISPLAY (display)->egl_display;
+}
+
+gboolean _gdk_mir_display_have_egl_khr_create_context (GdkDisplay *display)
+{
+ return GDK_MIR_DISPLAY (display)->have_egl_khr_create_context;
+}
+
+gboolean _gdk_mir_display_have_egl_buffer_age (GdkDisplay *display)
+{
+ /* FIXME: this is not really supported by mir yet (despite is advertised) */
+ // return GDK_MIR_DISPLAY (display)->have_egl_buffer_age;
+ return FALSE;
+}
+
+gboolean _gdk_mir_display_have_egl_swap_buffers_with_damage (GdkDisplay *display)
+{
+ /* FIXME: this is not really supported by mir yet (despite is advertised) */
+ // return GDK_MIR_DISPLAY (display)->have_egl_swap_buffers_with_damage;
+ return FALSE;
+}
+
+gboolean _gdk_mir_display_have_egl_surfaceless_context (GdkDisplay *display)
+{
+ return GDK_MIR_DISPLAY (display)->have_egl_surfaceless_context;
+}
+
+
+static void
gdk_mir_display_init (GdkMirDisplay *display)
{
display->event_source = _gdk_mir_event_source_new (GDK_DISPLAY (display));
@@ -545,4 +731,5 @@ gdk_mir_display_class_init (GdkMirDisplayClass *klass)
display_class->convert_selection = gdk_mir_display_convert_selection;
display_class->text_property_to_utf8_list = gdk_mir_display_text_property_to_utf8_list;
display_class->utf8_to_string_target = gdk_mir_display_utf8_to_string_target;
+ display_class->make_gl_context_current = gdk_mir_display_make_gl_context_current;
}
diff --git a/gdk/mir/gdkmirglcontext.c b/gdk/mir/gdkmirglcontext.c
new file mode 100644
index 0000000000..2868baea07
--- /dev/null
+++ b/gdk/mir/gdkmirglcontext.c
@@ -0,0 +1,125 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkmirglcontext.c: Mir specific OpenGL wrappers
+ *
+ * Copyright © 2014 Canonical Ltd
+ *
+ * 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 "gdkmir-private.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+
+G_DEFINE_TYPE (GdkMirGLContext, gdk_mir_gl_context, GDK_TYPE_GL_CONTEXT)
+
+static void
+gdk_mir_gl_context_update (GdkGLContext *context)
+{
+ GdkWindow *window = gdk_gl_context_get_window (context);
+ int width, height;
+
+ gdk_gl_context_make_current (context);
+
+ 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);
+}
+
+static void
+gdk_mir_gl_context_end_frame (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);
+ GdkMirGLContext *context_mir = GDK_MIR_GL_CONTEXT (context);
+ EGLDisplay egl_display = _gdk_mir_display_get_egl_display (display);
+ EGLSurface egl_surface;
+
+ gdk_gl_context_make_current (context);
+
+ egl_surface = _gdk_mir_window_get_egl_surface (window,
+ context_mir->egl_config);
+
+ if (_gdk_mir_display_have_egl_swap_buffers_with_damage (display))
+ {
+ 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 (egl_display, egl_surface, rects, n_rects);
+ g_free (rects);
+ }
+ else
+ {
+ eglSwapBuffers (egl_display, egl_surface);
+ }
+}
+
+static void
+gdk_mir_gl_context_dispose (GObject *gobject)
+{
+ GdkMirGLContext *context_mir = GDK_MIR_GL_CONTEXT (gobject);
+
+ if (context_mir->egl_context != NULL)
+ {
+ GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+ GdkWindow *window = gdk_gl_context_get_window (context);
+ GdkDisplay *display = gdk_window_get_display (window);
+ EGLDisplay egl_display = _gdk_mir_display_get_egl_display (display);
+
+ if (eglGetCurrentContext () == context_mir->egl_context)
+ eglMakeCurrent (egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ GDK_NOTE (OPENGL, g_print ("Destroying EGL context\n"));
+
+ eglDestroyContext (egl_display, context_mir->egl_context);
+ context_mir->egl_context = NULL;
+ }
+
+ G_OBJECT_CLASS (gdk_mir_gl_context_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_mir_gl_context_class_init (GdkMirGLContextClass *klass)
+{
+ GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ context_class->update = gdk_mir_gl_context_update;
+ context_class->end_frame = gdk_mir_gl_context_end_frame;
+ gobject_class->dispose = gdk_mir_gl_context_dispose;
+}
+
+static void
+gdk_mir_gl_context_init (GdkMirGLContext *self)
+{
+}
diff --git a/gdk/mir/gdkmirwindowimpl.c b/gdk/mir/gdkmirwindowimpl.c
index 418724be42..aa029f5e4a 100644
--- a/gdk/mir/gdkmirwindowimpl.c
+++ b/gdk/mir/gdkmirwindowimpl.c
@@ -25,6 +25,7 @@
#include "gdkwindowimpl.h"
#include "gdkinternals.h"
+#include "gdkintl.h"
#include "gdkdisplayprivate.h"
#include "gdkdeviceprivate.h"
@@ -32,6 +33,8 @@
#define GDK_IS_WINDOW_IMPL_MIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_MIR))
#define GDK_MIR_WINDOW_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImplClass))
+#define MAX_EGL_ATTRS 30
+
typedef struct _GdkMirWindowImplClass GdkMirWindowImplClass;
struct _GdkMirWindowImpl
@@ -64,6 +67,13 @@ struct _GdkMirWindowImpl
/* Cairo context for current frame */
cairo_surface_t *cairo_surface;
+ /* Egl surface for the current mir surface */
+ EGLSurface egl_surface;
+
+ /* Dummy MIR and EGL surfaces */
+ MirSurface *dummy_surface;
+ EGLSurface dummy_egl_surface;
+
/* TRUE if the window can be seen */
gboolean visible;
@@ -135,12 +145,6 @@ gdk_mir_window_impl_init (GdkMirWindowImpl *impl)
impl->surface_state = mir_surface_state_unknown;
}
-static MirConnection *
-get_connection (GdkWindow *window)
-{
- return gdk_mir_display_get_mir_connection (gdk_window_get_display (window));
-}
-
static void
set_surface_state (GdkMirWindowImpl *impl,
MirSurfaceState state)
@@ -173,13 +177,32 @@ event_cb (MirSurface *surface,
_gdk_mir_event_source_queue (context, event);
}
+static MirSurface *
+create_mir_surface (GdkDisplay *display,
+ gint width,
+ gint height,
+ MirBufferUsage buffer_usage)
+{
+ MirSurfaceParameters parameters;
+ MirConnection *connection;
+
+ parameters.name = "GTK+ Mir";
+ parameters.width = width;
+ parameters.height = height;
+ parameters.pixel_format = _gdk_mir_display_get_pixel_format (display, buffer_usage);
+ parameters.buffer_usage = buffer_usage;
+ parameters.output_id = mir_display_output_id_invalid;
+
+ connection = gdk_mir_display_get_mir_connection (display);
+
+ return mir_connection_create_surface_sync (connection, &parameters);
+}
+
static void
-ensure_surface (GdkWindow *window)
+ensure_surface_full (GdkWindow *window,
+ MirBufferUsage buffer_usage)
{
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
- MirPixelFormat formats[mir_pixel_formats], pixel_format = mir_pixel_format_invalid;
- unsigned int n_formats, i;
- MirSurfaceParameters parameters;
MirEventDelegate event_delegate = { event_cb, NULL };
GdkMirWindowReference *window_ref;
@@ -193,34 +216,17 @@ ensure_surface (GdkWindow *window)
event_delegate.context = window_ref;
- // Should probably calculate this once?
- // Should prefer certain formats over others
- mir_connection_get_available_surface_formats (get_connection (window), formats, mir_pixel_formats, &n_formats);
- for (i = 0; i < n_formats; i++)
- if (formats[i] == mir_pixel_format_argb_8888)
- {
- pixel_format = formats[i];
- break;
- }
-
- parameters.name = "GTK+ Mir";
- parameters.width = window->width;
- parameters.height = window->height;
- parameters.pixel_format = pixel_format;
- parameters.buffer_usage = mir_buffer_usage_software;
- parameters.output_id = mir_display_output_id_invalid;
- impl->surface = mir_connection_create_surface_sync (get_connection (window), &parameters);
+ impl->surface = create_mir_surface (gdk_window_get_display (window),
+ window->width, window->height,
+ buffer_usage);
- MirGraphicsRegion region;
MirEvent resize_event;
- mir_surface_get_graphics_region (impl->surface, &region);
-
/* Send the initial configure with the size the server gave... */
resize_event.resize.type = mir_event_type_resize;
resize_event.resize.surface_id = 0;
- resize_event.resize.width = region.width;
- resize_event.resize.height = region.height;
+ resize_event.resize.width = window->width;
+ resize_event.resize.height = window->height;
_gdk_mir_event_source_queue (window_ref, &resize_event);
@@ -230,6 +236,14 @@ ensure_surface (GdkWindow *window)
}
static void
+ensure_surface (GdkWindow *window)
+{
+ ensure_surface_full (window, window->gl_paint_context ?
+ mir_buffer_usage_hardware :
+ mir_buffer_usage_software);
+}
+
+static void
ensure_no_surface (GdkWindow *window)
{
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
@@ -237,15 +251,30 @@ ensure_no_surface (GdkWindow *window)
if (impl->cairo_surface)
{
cairo_surface_finish (impl->cairo_surface);
- cairo_surface_destroy (impl->cairo_surface);
- impl->cairo_surface = NULL;
+ g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
}
- if (impl->surface)
+ if (window->gl_paint_context)
{
- mir_surface_release_sync (impl->surface);
- impl->surface = NULL;
+ GdkDisplay *display = gdk_window_get_display (window);
+ EGLDisplay egl_display = _gdk_mir_display_get_egl_display (display);
+
+ if (impl->egl_surface)
+ {
+ eglDestroySurface (egl_display, impl->egl_surface);
+ impl->egl_surface = NULL;
+ }
+
+ if (impl->dummy_egl_surface)
+ {
+ eglDestroySurface (egl_display, impl->dummy_egl_surface);
+ impl->dummy_egl_surface = NULL;
+ }
+
+ g_clear_pointer (&impl->dummy_surface, mir_surface_release_sync);
}
+
+ g_clear_pointer(&impl->surface, mir_surface_release_sync);
}
static void
@@ -303,11 +332,7 @@ send_buffer (GdkWindow *window)
mir_surface_swap_buffers_sync (impl->surface);
/* The Cairo context is no longer valid */
- if (impl->cairo_surface)
- {
- cairo_surface_destroy (impl->cairo_surface);
- impl->cairo_surface = NULL;
- }
+ g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
}
static cairo_surface_t *
@@ -316,7 +341,7 @@ gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window)
//g_printerr ("gdk_mir_window_impl_ref_cairo_surface window=%p\n", window);
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
MirGraphicsRegion region;
- cairo_format_t pixel_format = CAIRO_FORMAT_INVALID;
+ cairo_format_t pixel_format = CAIRO_FORMAT_ARGB32;
cairo_surface_t *cairo_surface;
cairo_t *c;
@@ -327,31 +352,16 @@ gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window)
}
/* Transient windows get rendered into a buffer and copied onto their parent */
- if (impl->transient_for)
+ if (impl->transient_for || window->gl_paint_context)
{
- cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, window->width, window->height);
+ cairo_surface = cairo_image_surface_create (pixel_format, window->width, window->height);
}
else
{
ensure_surface (window);
mir_surface_get_graphics_region (impl->surface, &region);
-
- // FIXME: Should calculate this once
- switch (region.pixel_format)
- {
- case mir_pixel_format_argb_8888:
- pixel_format = CAIRO_FORMAT_ARGB32;
- break;
- default:
- case mir_pixel_format_abgr_8888:
- case mir_pixel_format_xbgr_8888:
- case mir_pixel_format_xrgb_8888:
- case mir_pixel_format_bgr_888:
- // uh-oh...
- g_printerr ("Unsupported pixel format %d\n", region.pixel_format);
- break;
- }
+ g_assert (region.pixel_format == mir_pixel_format_argb_8888);
cairo_surface = cairo_image_surface_create_for_data ((unsigned char *) region.vaddr,
pixel_format,
@@ -421,10 +431,13 @@ gdk_mir_window_impl_show (GdkWindow *window,
/* Make sure there's a surface to see */
ensure_surface (window);
- /* Make sure something is rendered and then show first frame */
- s = gdk_mir_window_impl_ref_cairo_surface (window);
- send_buffer (window);
- cairo_surface_destroy (s);
+ if (!window->gl_paint_context)
+ {
+ /* Make sure something is rendered and then show first frame */
+ s = gdk_mir_window_impl_ref_cairo_surface (window);
+ send_buffer (window);
+ cairo_surface_destroy (s);
+ }
}
static void
@@ -666,7 +679,7 @@ gdk_mir_window_impl_end_paint (GdkWindow *window)
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
//g_printerr ("gdk_mir_window_impl_end_paint window=%p\n", window);
- if (impl->visible)
+ if (impl->visible && !window->current_paint.use_gl)
send_buffer (window);
}
@@ -1245,6 +1258,267 @@ gdk_mir_window_impl_set_shadow_width (GdkWindow *window,
g_printerr ("gdk_mir_window_impl_set_shadow_width window=%p\n", window);
}
+static gboolean
+find_eglconfig_for_window (GdkWindow *window,
+ EGLConfig *egl_config_out,
+ GError **error)
+{
+ GdkDisplay *display = gdk_window_get_display (window);
+ EGLDisplay *egl_display = _gdk_mir_display_get_egl_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++] = 1;
+ attrs[i++] = EGL_GREEN_SIZE;
+ attrs[i++] = 1;
+ attrs[i++] = EGL_BLUE_SIZE;
+ attrs[i++] = 1;
+
+ 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 (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 (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;
+}
+
+static GdkGLContext *
+gdk_mir_window_impl_create_gl_context (GdkWindow *window,
+ gboolean attached,
+ GdkGLProfile profile,
+ GdkGLContext *share,
+ GError **error)
+{
+ GdkDisplay *display = gdk_window_get_display (window);
+ GdkMirGLContext *context;
+ EGLContext ctx;
+ EGLConfig config;
+ int i;
+ EGLint context_attribs[3];
+
+ if (!_gdk_mir_display_init_egl_display (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_DEFAULT)
+ profile = GDK_GL_PROFILE_LEGACY;
+
+ if (profile == GDK_GL_PROFILE_3_2_CORE &&
+ !_gdk_mir_display_have_egl_khr_create_context (display))
+ {
+ 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 (_gdk_mir_display_get_egl_display (display),
+ config,
+ share ? GDK_MIR_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_TYPE_MIR_GL_CONTEXT,
+ "display", display,
+ "window", window,
+ "profile", profile,
+ "shared-context", share,
+ NULL);
+
+ context->egl_config = config;
+ context->egl_context = ctx;
+ context->is_attached = attached;
+
+ return GDK_GL_CONTEXT (context);
+}
+
+static void
+gdk_mir_window_impl_invalidate_for_new_frame (GdkWindow *window,
+ cairo_region_t *update_area)
+{
+ cairo_rectangle_int_t window_rect;
+ GdkDisplay *display = gdk_window_get_display (window);
+ GdkMirGLContext *context_mir;
+ 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_mir = GDK_MIR_GL_CONTEXT (window->gl_paint_context);
+ buffer_age = 0;
+
+ egl_surface = _gdk_mir_window_get_egl_surface (window, context_mir->egl_config);
+
+ if (_gdk_mir_display_have_egl_buffer_age (display))
+ {
+ gdk_gl_context_make_current (window->gl_paint_context);
+ eglQuerySurface (_gdk_mir_display_get_egl_display (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);
+ }
+}
+
+EGLSurface
+_gdk_mir_window_get_egl_surface (GdkWindow *window,
+ EGLConfig config)
+{
+ GdkMirWindowImpl *impl;
+
+ impl = GDK_MIR_WINDOW_IMPL (window->impl);
+
+ if (!impl->egl_surface)
+ {
+ EGLDisplay egl_display;
+ EGLNativeWindowType egl_window;
+
+ ensure_no_surface (window);
+ ensure_surface_full (window, mir_buffer_usage_hardware);
+
+ egl_display = _gdk_mir_display_get_egl_display (gdk_window_get_display (window));
+ egl_window = (EGLNativeWindowType) mir_surface_get_egl_native_window (impl->surface);
+
+ impl->egl_surface =
+ eglCreateWindowSurface (egl_display, config, egl_window, NULL);
+ }
+
+ return impl->egl_surface;
+}
+
+EGLSurface
+_gdk_mir_window_get_dummy_egl_surface (GdkWindow *window,
+ EGLConfig config)
+{
+ GdkMirWindowImpl *impl;
+
+ impl = GDK_MIR_WINDOW_IMPL (window->impl);
+
+ if (!impl->dummy_egl_surface)
+ {
+ GdkDisplay *display;
+ EGLDisplay egl_display;
+ EGLNativeWindowType egl_window;
+
+ display = gdk_window_get_display (window);
+ impl->dummy_surface = create_mir_surface (display, 1, 1,
+ mir_buffer_usage_hardware);
+
+ egl_display = _gdk_mir_display_get_egl_display (display);
+ egl_window = (EGLNativeWindowType) mir_surface_get_egl_native_window (impl->surface);
+
+ impl->dummy_egl_surface =
+ eglCreateWindowSurface (egl_display, config, egl_window, NULL);
+ }
+
+ return impl->dummy_egl_surface;
+}
+
static void
gdk_mir_window_impl_class_init (GdkMirWindowImplClass *klass)
{
@@ -1333,4 +1607,6 @@ gdk_mir_window_impl_class_init (GdkMirWindowImplClass *klass)
impl_class->get_scale_factor = gdk_mir_window_impl_get_scale_factor;
impl_class->set_opaque_region = gdk_mir_window_impl_set_opaque_region;
impl_class->set_shadow_width = gdk_mir_window_impl_set_shadow_width;
+ impl_class->create_gl_context = gdk_mir_window_impl_create_gl_context;
+ impl_class->invalidate_for_new_frame = gdk_mir_window_impl_invalidate_for_new_frame;
}