diff options
author | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2014-11-18 22:23:52 +0100 |
---|---|---|
committer | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2014-11-20 04:33:38 +0100 |
commit | 6e9db05601e33ccfc71bd55c17f114caffd6f93b (patch) | |
tree | a7254541eccf77b3c8bb3d5dbe6395aebc63e3ad | |
parent | 45cfb405c0e34c69ccc483455d31febca60abb33 (diff) | |
download | gtk+-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.am | 1 | ||||
-rw-r--r-- | gdk/mir/gdkmir-private.h | 42 | ||||
-rw-r--r-- | gdk/mir/gdkmir.h | 10 | ||||
-rw-r--r-- | gdk/mir/gdkmirdisplay.c | 187 | ||||
-rw-r--r-- | gdk/mir/gdkmirglcontext.c | 125 | ||||
-rw-r--r-- | gdk/mir/gdkmirwindowimpl.c | 408 |
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, ¶meters); +} + 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), ¶meters); + 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, ®ion); - /* 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, ®ion); - - // 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; } |