[mutter] frames: Remove frame border pixel caching and related optimizations



commit 6fb857cb23fa0b5524fb1611071a9b79e9e09930
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon May 21 12:48:31 2012 -0400

    frames: Remove frame border pixel caching and related optimizations
    
    Since we now cache windows in the X server, we don't really need to cache
    them here. Since we are redirecting windows in most cases, we're not gaining
    anything except added memory usage. Additionally, remove the clip to screen
    optimization - if a window is partially off-screen, we still need to draw
    the entire thing as redirection means we won't get an expose event for it.
    
    Additionally, when introducing invisible borders, something accidentally
    slipped through: we were getting expose events on the invisible borders,
    and they weren't in the cached pixels rect, so we were painting the theme
    for them, even if we didn't actually paint anything with cairo. Make sure
    to clip out the invisible borders instead of just the client rect so that
    we don't draw if our expose event is on the invisible borders.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=675111

 src/ui/frames.c |  350 ++++++-------------------------------------------------
 src/ui/frames.h |    4 -
 2 files changed, 35 insertions(+), 319 deletions(-)
---
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 9e87f67..3ec67c9 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -97,7 +97,6 @@ static MetaFrameControl get_control  (MetaFrames        *frames,
                                       MetaUIFrame       *frame,
                                       int                x,
                                       int                y);
-static void invalidate_all_caches (MetaFrames *frames);
 static void invalidate_whole_window (MetaFrames *frames,
                                      MetaUIFrame *frame);
 
@@ -261,10 +260,6 @@ meta_frames_init (MetaFrames *frames)
   
   frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
 
-  frames->invalidate_cache_timeout_id = 0;
-  frames->invalidate_frames = NULL;
-  frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
-
   frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   g_free, g_object_unref);
   update_style_contexts (frames);
@@ -331,90 +326,13 @@ meta_frames_finalize (GObject *object)
   meta_prefs_remove_listener (prefs_changed_callback, frames);
   
   g_hash_table_destroy (frames->text_heights);
-
-  invalidate_all_caches (frames);
-  if (frames->invalidate_cache_timeout_id)
-    g_source_remove (frames->invalidate_cache_timeout_id);
   
   g_assert (g_hash_table_size (frames->frames) == 0);
   g_hash_table_destroy (frames->frames);
-  g_hash_table_destroy (frames->cache);
 
   G_OBJECT_CLASS (meta_frames_parent_class)->finalize (object);
 }
 
-typedef struct
-{
-  cairo_rectangle_int_t rect;
-  cairo_surface_t *pixmap;
-} CachedFramePiece;
-
-typedef struct
-{
-  /* Caches of the four rendered sides in a MetaFrame.
-   * Order: top (titlebar), left, right, bottom.
-   */
-  CachedFramePiece piece[4];
-} CachedPixels;
-
-static CachedPixels *
-get_cache (MetaFrames *frames,
-           MetaUIFrame *frame)
-{
-  CachedPixels *pixels;
-  
-  pixels = g_hash_table_lookup (frames->cache, frame);
-
-  if (!pixels)
-    {
-      pixels = g_new0 (CachedPixels, 1);
-      g_hash_table_insert (frames->cache, frame, pixels);
-    }
-
-  return pixels;
-}
-
-static void
-invalidate_cache (MetaFrames *frames,
-                  MetaUIFrame *frame)
-{
-  CachedPixels *pixels = get_cache (frames, frame);
-  int i;
-  
-  for (i = 0; i < 4; i++)
-    if (pixels->piece[i].pixmap)
-      cairo_surface_destroy (pixels->piece[i].pixmap);
-  
-  g_free (pixels);
-  g_hash_table_remove (frames->cache, frame);
-}
-
-static void
-invalidate_all_caches (MetaFrames *frames)
-{
-  GList *l;
-
-  for (l = frames->invalidate_frames; l; l = l->next)
-    {
-      MetaUIFrame *frame = l->data;
-
-      invalidate_cache (frames, frame);
-    }
-  
-  g_list_free (frames->invalidate_frames);
-  frames->invalidate_frames = NULL;
-}
-
-static gboolean
-invalidate_cache_timeout (gpointer data)
-{
-  MetaFrames *frames = data;
-  
-  invalidate_all_caches (frames);
-  frames->invalidate_cache_timeout_id = 0;
-  return FALSE;
-}
-
 static void
 queue_recalc_func (gpointer key, gpointer value, gpointer data)
 {
@@ -719,11 +637,6 @@ meta_frames_unmanage_window (MetaFrames *frames,
 
   if (frame)
     {
-      /* invalidating all caches ensures the frame
-       * is not actually referenced anymore
-       */
-      invalidate_all_caches (frames);
-      
       /* restore the cursor */
       meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                                    frame->xwindow,
@@ -1125,7 +1038,6 @@ redraw_control (MetaFrames *frames,
   rect = control_rect (control, &fgeom);
 
   gdk_window_invalidate_rect (frame->window, rect, FALSE);
-  invalidate_cache (frames, frame);
 }
 
 static gboolean
@@ -1899,222 +1811,50 @@ setup_bg_cr (cairo_t *cr, GdkWindow *window, int x_offset, int y_offset)
     }
 }
 
-/* Returns a pixmap with a piece of the windows frame painted on it.
-*/
-
-static cairo_surface_t *
-generate_pixmap (MetaFrames            *frames,
-                 MetaUIFrame           *frame,
-                 cairo_rectangle_int_t *rect)
-{
-  cairo_surface_t *result;
-  cairo_t *cr;
-
-  /* do not create a pixmap for nonexisting areas */
-  if (rect->width <= 0 || rect->height <= 0)
-    return NULL;
-
-  result = gdk_window_create_similar_surface (frame->window,
-                                              CAIRO_CONTENT_COLOR,
-                                              rect->width, rect->height);
-  
-  cr = cairo_create (result);
-  cairo_translate (cr, -rect->x, -rect->y);
-
-  setup_bg_cr (cr, frame->window, 0, 0);
-  cairo_paint (cr);
-
-  meta_frames_paint (frames, frame, cr);
-
-  cairo_destroy (cr);
-
-  return result;
-}
-
-
 static void
-populate_cache (MetaFrames *frames,
-                MetaUIFrame *frame)
-{
-  MetaFrameBorders borders;
-  int width, height;
-  int frame_width, frame_height, screen_width, screen_height;
-  CachedPixels *pixels;
-  MetaFrameType frame_type;
-  MetaFrameFlags frame_flags;
-  int i;
-
-  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
-                 frame->xwindow,
-                 META_CORE_GET_FRAME_WIDTH, &frame_width,
-                 META_CORE_GET_FRAME_HEIGHT, &frame_height,
-                 META_CORE_GET_SCREEN_WIDTH, &screen_width,
-                 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
-                 META_CORE_GET_CLIENT_WIDTH, &width,
-                 META_CORE_GET_CLIENT_HEIGHT, &height,
-                 META_CORE_GET_FRAME_TYPE, &frame_type,
-                 META_CORE_GET_FRAME_FLAGS, &frame_flags,
-                 META_CORE_GET_END);
-
-  /* don't cache extremely large windows */
-  if (frame_width > 2 * screen_width ||
-      frame_height > 2 * screen_height)
-    {
-      return;
-    }
-  
-  meta_theme_get_frame_borders (meta_theme_get_current (),
-                                frame_type,
-                                frame->text_height,
-                                frame_flags,
-                                &borders);
-
-  pixels = get_cache (frames, frame);
-
-  /* Setup the rectangles for the four visible frame borders. First top, then
-   * left, right and bottom. Top and bottom extend to the invisible borders
-   * while left and right snugly fit in between:
-   *   -----
-   *   |   |
-   *   -----
-   */
-
-  /* width and height refer to the client window's
-   * size without any border added. */
-
-  /* top */
-  pixels->piece[0].rect.x = borders.invisible.left;
-  pixels->piece[0].rect.y = borders.invisible.top;
-  pixels->piece[0].rect.width = width + borders.visible.left + borders.visible.right;
-  pixels->piece[0].rect.height = borders.visible.top;
-
-  /* left */
-  pixels->piece[1].rect.x = borders.invisible.left;
-  pixels->piece[1].rect.y = borders.total.top;
-  pixels->piece[1].rect.height = height;
-  pixels->piece[1].rect.width = borders.visible.left;
-
-  /* right */
-  pixels->piece[2].rect.x = borders.total.left + width;
-  pixels->piece[2].rect.y = borders.total.top;
-  pixels->piece[2].rect.width = borders.visible.right;
-  pixels->piece[2].rect.height = height;
-
-  /* bottom */
-  pixels->piece[3].rect.x = borders.invisible.left;
-  pixels->piece[3].rect.y = borders.total.top + height;
-  pixels->piece[3].rect.width = width + borders.visible.left + borders.visible.right;
-  pixels->piece[3].rect.height = borders.visible.bottom;
-
-  for (i = 0; i < 4; i++)
-    {
-      CachedFramePiece *piece = &pixels->piece[i];
-      /* generate_pixmap() returns NULL for 0 width/height pieces, but
-       * does so cheaply so we don't need to cache the NULL return */
-      if (!piece->pixmap)
-        piece->pixmap = generate_pixmap (frames, frame, &piece->rect);
-    }
-  
-  if (frames->invalidate_cache_timeout_id)
-    g_source_remove (frames->invalidate_cache_timeout_id);
-  
-  frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
-
-  if (!g_list_find (frames->invalidate_frames, frame))
-    frames->invalidate_frames =
-      g_list_prepend (frames->invalidate_frames, frame);
-}
-
-static void
-clip_to_screen (cairo_region_t *region,
-                MetaUIFrame    *frame)
-{
-  cairo_rectangle_int_t frame_area;
-  cairo_rectangle_int_t screen_area = { 0, 0, 0, 0 };
-  cairo_region_t *tmp_region;
-  
-  /* Chop off stuff outside the screen; this optimization
-   * is crucial to handle huge client windows,
-   * like "xterm -geometry 1000x1000"
-   */
-  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
-                 frame->xwindow,
-                 META_CORE_GET_FRAME_X, &frame_area.x,
-                 META_CORE_GET_FRAME_Y, &frame_area.y,
-                 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
-                 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
-                 META_CORE_GET_SCREEN_WIDTH, &screen_area.width,
-                 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
-                 META_CORE_GET_END);
-
-  cairo_region_translate (region, frame_area.x, frame_area.y);
-
-  tmp_region = cairo_region_create_rectangle (&frame_area);
-  cairo_region_intersect (region, tmp_region);
-  cairo_region_destroy (tmp_region);
-
-  tmp_region = cairo_region_create_rectangle (&screen_area);
-  cairo_region_intersect (region, tmp_region);
-  cairo_region_destroy (tmp_region);
-
-  cairo_region_translate (region, - frame_area.x, - frame_area.y);
-}
-
-static void
-subtract_client_area (cairo_region_t *region,
-                      MetaUIFrame    *frame)
+clip_region_to_visible_frame_border (cairo_region_t *region,
+                                     MetaUIFrame    *frame)
 {
   cairo_rectangle_int_t area;
+  cairo_region_t *frame_border;
   MetaFrameFlags flags;
   MetaFrameType type;
   MetaFrameBorders borders;
-  cairo_region_t *tmp_region;
   Display *display;
+  int frame_width, frame_height;
   
   display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
   meta_core_get (display, frame->xwindow,
                  META_CORE_GET_FRAME_FLAGS, &flags,
                  META_CORE_GET_FRAME_TYPE, &type,
-                 META_CORE_GET_CLIENT_WIDTH, &area.width,
-                 META_CORE_GET_CLIENT_HEIGHT, &area.height,
+                 META_CORE_GET_FRAME_WIDTH, &frame_width,
+                 META_CORE_GET_FRAME_HEIGHT, &frame_height,
                  META_CORE_GET_END);
+
   meta_theme_get_frame_borders (meta_theme_get_current (),
                                 type, frame->text_height, flags, 
                                 &borders);
 
-  area.x = borders.total.left;
-  area.y = borders.total.top;
+  /* Visible frame rect */
+  area.x = borders.invisible.left;
+  area.y = borders.invisible.top;
+  area.width = frame_width - borders.invisible.left - borders.invisible.right;
+  area.height = frame_height - borders.invisible.top - borders.invisible.bottom;
 
-  tmp_region = cairo_region_create_rectangle (&area);
-  cairo_region_subtract (region, tmp_region);
-  cairo_region_destroy (tmp_region);
-}
+  frame_border = cairo_region_create_rectangle (&area);
 
-static void
-cached_pixels_draw (CachedPixels   *pixels,
-                    cairo_t        *cr,
-                    cairo_region_t *region)
-{
-  cairo_region_t *region_piece;
-  int i;
+  /* Client rect */
+  area.x += borders.visible.left;
+  area.y += borders.visible.top;
+  area.width -= borders.visible.left + borders.visible.right;
+  area.height -= borders.visible.top + borders.visible.bottom;
 
-  for (i = 0; i < 4; i++)
-    {
-      CachedFramePiece *piece;
-      piece = &pixels->piece[i];
-      
-      if (piece->pixmap)
-        {
-          cairo_set_source_surface (cr, piece->pixmap,
-                                    piece->rect.x, piece->rect.y);
-          cairo_paint (cr);
-          
-          region_piece = cairo_region_create_rectangle (&piece->rect);
-          cairo_region_subtract (region, region_piece);
-          cairo_region_destroy (region_piece);
-        }
-    }
+  /* Visible frame border */
+  cairo_region_subtract_rectangle (frame_border, &area);
+  cairo_region_intersect (region, frame_border);
+
+  cairo_region_destroy (frame_border);
 }
 
 static gboolean
@@ -2123,10 +1863,8 @@ meta_frames_draw (GtkWidget *widget,
 {
   MetaUIFrame *frame;
   MetaFrames *frames;
-  CachedPixels *pixels;
-  cairo_region_t *region;
   cairo_rectangle_int_t clip;
-  int i, n_areas;
+  cairo_region_t *region;
   cairo_surface_t *target;
 
   frames = META_FRAMES (widget);
@@ -2138,40 +1876,23 @@ meta_frames_draw (GtkWidget *widget,
   if (frame == NULL)
     return FALSE;
 
-  populate_cache (frames, frame);
-
   region = cairo_region_create_rectangle (&clip);
-  
-  pixels = get_cache (frames, frame);
-
-  cached_pixels_draw (pixels, cr, region);
-  
-  clip_to_screen (region, frame);
-  subtract_client_area (region, frame);
-
-  n_areas = cairo_region_num_rectangles (region);
-
-  for (i = 0; i < n_areas; i++)
-    {
-      cairo_rectangle_int_t area;
-
-      cairo_region_get_rectangle (region, i, &area);
-
-      cairo_save (cr);
-
-      cairo_rectangle (cr, area.x, area.y, area.width, area.height);
-      cairo_clip (cr);
+  clip_region_to_visible_frame_border (region, frame);
 
-      cairo_push_group (cr);
+  if (cairo_region_is_empty (region))
+    goto out;
 
-      meta_frames_paint (frames, frame, cr);
+  gdk_cairo_region (cr, region);
+  cairo_clip (cr);
 
-      cairo_pop_group_to_source (cr);
-      cairo_paint (cr);
+  cairo_save (cr);
+  setup_bg_cr (cr, frame->window, 0, 0);
+  cairo_paint (cr);
+  cairo_restore (cr);
 
-      cairo_restore (cr);
-    }
+  meta_frames_paint (frames, frame, cr);
 
+ out:
   cairo_region_destroy (region);
   
   return TRUE;
@@ -2615,5 +2336,4 @@ invalidate_whole_window (MetaFrames *frames,
                          MetaUIFrame *frame)
 {
   gdk_window_invalidate_rect (frame->window, NULL, FALSE);
-  invalidate_cache (frames, frame);
 }
diff --git a/src/ui/frames.h b/src/ui/frames.h
index b42c651..be238a8 100644
--- a/src/ui/frames.h
+++ b/src/ui/frames.h
@@ -97,10 +97,6 @@ struct _MetaFrames
 
   GtkStyleContext *normal_style;
   GHashTable *style_variants;
-
-  int invalidate_cache_timeout_id;
-  GList *invalidate_frames;
-  GHashTable *cache;
 };
 
 struct _MetaFramesClass



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