From d3831729a0fb35f4272bd93d4c0dfe21f9358acb Mon Sep 17 00:00:00 2001 From: Adel Gadllah Date: Sat, 27 Aug 2011 11:43:09 +0200 Subject: [PATCH] Unredirect fullscreen windows Some apps that do a lot of rendering on the screen like games, mostly run in fullscreen where there is no need for them to be redirected doing so does add an overhead; while performance is critical for those apps. This can be disabled / enabled at runtime using meta_enable_unredirect_for_screen / meta_disable_unredirect_for_screen https://bugzilla.gnome.org/show_bug.cgi?id=597014 --- src/compositor/compositor-private.h | 5 + src/compositor/compositor.c | 103 +++++++++++++++++++++ src/compositor/meta-window-actor-private.h | 8 ++ src/compositor/meta-window-actor.c | 66 ++++++++++++- src/compositor/meta-window-group.c | 18 +++- src/meta/compositor-mutter.h | 3 + 6 files changed, 200 insertions(+), 3 deletions(-) diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 90dc63b82..23f639fd2 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -8,6 +8,7 @@ #include #include #include "meta-plugin-manager.h" +#include "meta-window-actor-private.h" #include typedef struct _MetaCompScreen MetaCompScreen; @@ -41,6 +42,10 @@ struct _MetaCompScreen GHashTable *windows_by_xid; Window output; + /* Used for unredirecting fullscreen windows */ + guint disable_unredirect_count; + MetaWindowActor *unredirected_window; + /* Before we create the output window */ XserverRegion pending_input_region; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 68425d8f1..9c85c7d97 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -598,6 +598,38 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor, XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); } +/* + * Shapes the cow so that the given window is exposed, + * when xwin is None it clears the shape again + */ +static void +meta_shape_cow_for_window (MetaScreen *screen, + Window xwin) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen)); + + if (xwin == None) + XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); + else + { + XserverRegion output_region; + XRectangle screen_rect; + int width, height; + + meta_screen_get_size (screen, &width, &height); + screen_rect.x = 0; + screen_rect.y = 0; + screen_rect.width = width; + screen_rect.height = height; + + output_region = XFixesCreateRegionFromWindow (xdisplay, xwin, WindowRegionBounding); + XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); + XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region); + XFixesDestroyRegion (xdisplay, output_region); + } +} + void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window) @@ -618,12 +650,25 @@ meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window) { MetaWindowActor *window_actor = NULL; + MetaScreen *screen; + MetaCompScreen *info; DEBUG_TRACE ("meta_compositor_remove_window\n"); window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (!window_actor) return; + screen = meta_window_get_screen (window); + info = meta_screen_get_compositor_data (screen); + + if (window_actor == info->unredirected_window) + { + meta_window_actor_set_redirected (window_actor, TRUE); + meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)), + None); + info->unredirected_window = NULL; + } + meta_window_actor_destroy (window_actor); } @@ -1097,6 +1142,33 @@ static void pre_paint_windows (MetaCompScreen *info) { GList *l; + MetaWindowActor *top_window; + MetaWindowActor *expected_unredirected_window = NULL; + + top_window = g_list_last (info->windows)->data; + + if (meta_window_actor_should_unredirect (top_window) && + info->disable_unredirect_count == 0) + expected_unredirected_window = top_window; + + if (info->unredirected_window != expected_unredirected_window) + { + if (info->unredirected_window != NULL) + { + meta_window_actor_set_redirected (info->unredirected_window, TRUE); + meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)), + None); + } + + if (expected_unredirected_window != NULL) + { + meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)), + meta_window_actor_get_x_window (top_window)); + meta_window_actor_set_redirected (top_window, FALSE); + } + + info->unredirected_window = expected_unredirected_window; + } for (l = info->windows; l; l = l->next) meta_window_actor_pre_paint (l->data); @@ -1200,6 +1272,37 @@ meta_get_overlay_window (MetaScreen *screen) return info->output; } +/** + * meta_disable_unredirect_for_screen: + * @screen: a #MetaScreen + * + * Disables unredirection, can be usefull in situations where having + * unredirected windows is undesireable like when recording a video. + * + */ +void +meta_disable_unredirect_for_screen (MetaScreen *screen) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + if (info != NULL) + info->disable_unredirect_count = info->disable_unredirect_count + 1; +} + +/** + * meta_enable_unredirect_for_screen: + * @screen: a #MetaScreen + * + * Enables unredirection which reduces the overhead for apps like games. + * + */ +void +meta_enable_unredirect_for_screen (MetaScreen *screen) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + if (info != NULL) + info->disable_unredirect_count = MAX(0, info->disable_unredirect_count - 1); +} + #define FLASH_TIME_MS 50 static void diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 79aafb63e..97e314049 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -26,10 +26,18 @@ void meta_window_actor_unmaximize (MetaWindowActor *self, void meta_window_actor_process_damage (MetaWindowActor *self, XDamageNotifyEvent *event); + void meta_window_actor_pre_paint (MetaWindowActor *self); void meta_window_actor_invalidate_shadow (MetaWindowActor *self); +void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state); + +gboolean meta_window_actor_should_unredirect (MetaWindowActor *self); + +void meta_window_actor_get_shape_bounds (MetaWindowActor *self, + cairo_rectangle_int_t *bounds); + gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self); void meta_window_actor_sync_actor_position (MetaWindowActor *self); void meta_window_actor_sync_visibility (MetaWindowActor *self); diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index c41dae9d7..11bd6aba1 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -114,6 +114,8 @@ struct _MetaWindowActorPrivate guint no_shadow : 1; guint no_more_x_calls : 1; + + guint unredirected : 1; }; enum @@ -575,7 +577,7 @@ meta_window_actor_get_shadow_params (MetaWindowActor *self, params); } -static void +void meta_window_actor_get_shape_bounds (MetaWindowActor *self, cairo_rectangle_int_t *bounds) { @@ -1210,6 +1212,62 @@ meta_window_actor_detach (MetaWindowActor *self) meta_window_actor_queue_create_pixmap (self); } +gboolean +meta_window_actor_should_unredirect (MetaWindowActor *self) +{ + MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); + MetaScreen *screen = meta_window_get_screen (metaWindow); + + if (meta_window_is_override_redirect (metaWindow)) + { + int screen_width, screen_height; + MetaRectangle window_rect; + meta_screen_get_size (screen, &screen_width, &screen_height); + meta_window_get_outer_rect (metaWindow, &window_rect); + + if (window_rect.x == 0 && window_rect.y == 0 && + window_rect.width == screen_width && window_rect.height == screen_height) + return TRUE; + else + { + int num_monitors = meta_screen_get_n_monitors (screen); + int i; + MetaRectangle monitor_rect; + + for (i = 0; i < num_monitors; i++) + { + meta_screen_get_monitor_geometry (screen , i, &monitor_rect); + if (monitor_rect.x == window_rect.x && monitor_rect.y == window_rect.y && + monitor_rect.width == window_rect.width && monitor_rect.height == window_rect.height) + return TRUE; + } + } + } + + return FALSE; +} + +void +meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state) +{ + MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); + + Display *xdisplay = meta_display_get_xdisplay (meta_window_get_display (metaWindow)); + Window xwin = meta_window_actor_get_x_window (self); + + if (state) + { + XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); + meta_window_actor_queue_create_pixmap (self); + self->priv->unredirected = FALSE; + } + else + { + XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); + self->priv->unredirected = TRUE; + } +} + void meta_window_actor_destroy (MetaWindowActor *self) { @@ -1945,6 +2003,10 @@ meta_window_actor_process_damage (MetaWindowActor *self, priv->received_damage = TRUE; + /* Drop damage event for unredirected windows */ + if (self->priv->unredirected) + return; + if (is_frozen (self)) { /* The window is frozen due to an effect in progress: we ignore damage @@ -2226,7 +2288,7 @@ meta_window_actor_pre_paint (MetaWindowActor *self) return; } - if (priv->received_damage) + if (priv->received_damage && !self->unredirected) { meta_error_trap_push (display); XDamageSubtract (xdisplay, priv->damage, None, None); diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index cd42e69ad..16232199a 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -7,6 +7,7 @@ #include /* for gdk_rectangle_intersect() */ +#include "compositor-private.h" #include "meta-window-actor-private.h" #include "meta-window-group.h" #include "meta-background-actor-private.h" @@ -104,10 +105,19 @@ static void meta_window_group_paint (ClutterActor *actor) { cairo_region_t *visible_region; + cairo_region_t *unredirected_window_region = NULL; ClutterActor *stage; - cairo_rectangle_int_t visible_rect; + cairo_rectangle_int_t visible_rect, unredirected_rect; GList *children, *l; + MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); + MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen); + if (info->unredirected_window != NULL) + { + meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect); + unredirected_window_region = cairo_region_create_rectangle (&unredirected_rect); + } + /* We walk the list from top to bottom (opposite of painting order), * and subtract the opaque area of each window out of the visible * region that we pass to the windows below. @@ -127,6 +137,9 @@ meta_window_group_paint (ClutterActor *actor) visible_region = cairo_region_create_rectangle (&visible_rect); + if (unredirected_window_region) + cairo_region_subtract (visible_region, unredirected_window_region); + for (l = children; l; l = l->next) { if (!CLUTTER_ACTOR_IS_VISIBLE (l->data)) @@ -164,6 +177,9 @@ meta_window_group_paint (ClutterActor *actor) cairo_region_destroy (visible_region); + if (unredirected_window_region) + cairo_region_destroy (unredirected_window_region); + CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); /* Now that we are done painting, unset the visible regions (they will diff --git a/src/meta/compositor-mutter.h b/src/meta/compositor-mutter.h index 4b7b78479..5be1f0e17 100644 --- a/src/meta/compositor-mutter.h +++ b/src/meta/compositor-mutter.h @@ -39,6 +39,9 @@ Window meta_get_overlay_window (MetaScreen *screen); GList *meta_get_window_actors (MetaScreen *screen); ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen); +void meta_disable_unredirect_for_screen (MetaScreen *screen); +void meta_enable_unredirect_for_screen (MetaScreen *screen); + ClutterActor *meta_get_background_actor_for_screen (MetaScreen *screen); #endif