]> git.sur5r.net Git - i3/i3/commitdiff
optimization: Render on pixmaps and copy the result on Stack_Wins
authorMichael Stapelberg <michael@stapelberg.de>
Fri, 17 Jul 2009 16:32:40 +0000 (18:32 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Fri, 17 Jul 2009 16:32:40 +0000 (18:32 +0200)
This should speed up the rendering of Stack_Wins with many window
decorations and it should considerably reduce flicker.

include/data.h
include/i3.h
include/xcb.h
src/layout.c
src/mainx.c
src/util.c
src/xcb.c

index 2776d5065ee12e4789ac7f82372772a19836b8e6..3288cb8d03e0533d36e2ff4d587cbc16ce32420a 100644 (file)
@@ -101,6 +101,22 @@ struct Colorpixel {
         SLIST_ENTRY(Colorpixel) colorpixels;
 };
 
+struct Cached_Pixmap {
+        xcb_pixmap_t id;
+
+        /* We’re going to paint on it, so a graphics context will be needed */
+        xcb_gcontext_t gc;
+
+        /* The rect with which the pixmap was created */
+        Rect rect;
+
+        /* The rect of the object to which this pixmap belongs. Necessary to
+         * find out when we need to re-create the pixmap. */
+        Rect *referred_rect;
+
+        xcb_drawable_t referred_drawable;
+};
+
 /**
  * Contains data for the windows needed to draw the titlebars on in stacking
  * mode
@@ -108,7 +124,7 @@ struct Colorpixel {
  */
 struct Stack_Window {
         xcb_window_t window;
-        xcb_gcontext_t gc;
+        struct Cached_Pixmap pixmap;
         Rect rect;
 
         /** Backpointer to the container this stack window is in */
index ccf7a4951552612d00407bc86c429e5c435d9700..a489b42f4556fd262115a934426d711040208de7 100644 (file)
@@ -30,6 +30,7 @@ extern TAILQ_HEAD(assignments_head, Assignment) assignments;
 extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
 extern xcb_event_handlers_t evenths;
 extern int num_screens;
+extern uint8_t root_depth;
 extern xcb_atom_t atoms[NUM_ATOMS];
 
 #endif
index de74bab6675e59d8b46d24fac0e428b7ce93c356..b540a5cc18773c976248527f63da3990e04cd295 100644 (file)
@@ -143,4 +143,13 @@ void xcb_get_numlock_mask(xcb_connection_t *conn);
  */
 void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window);
 
+/**
+ *
+ * Prepares the given Cached_Pixmap for usage (checks whether the size of the
+ * object this pixmap is related to (e.g. a window) has changed and re-creates
+ * the pixmap if so).
+ *
+ */
+void cached_pixmap_prepare(xcb_connection_t *conn, struct Cached_Pixmap *pixmap);
+
 #endif
index 4f132aea8cc2d8d1f54f2f902b2880a1c6429c5a..89c561eae83ab79a3071769ea46db477cc19c216 100644 (file)
@@ -362,6 +362,9 @@ void render_container(xcb_connection_t *conn, Container *container) {
                         xcb_configure_window(conn, stack_win->window, mask, values);
                 }
 
+                /* Prepare the pixmap for usage */
+                cached_pixmap_prepare(conn, &(stack_win->pixmap));
+
                 /* Render the decorations of all clients */
                 CIRCLEQ_FOREACH(client, &(container->clients), clients) {
                         /* If the client is in fullscreen mode, it does not get reconfigured */
@@ -384,9 +387,12 @@ void render_container(xcb_connection_t *conn, Container *container) {
 
                         client->force_reconfigure = false;
 
-                        decorate_window(conn, client, stack_win->window, stack_win->gc,
+                        decorate_window(conn, client, stack_win->pixmap.id, stack_win->pixmap.gc,
                                         current_client++ * decoration_height);
                 }
+
+                xcb_copy_area(conn, stack_win->pixmap.id, stack_win->window, stack_win->pixmap.gc,
+                              0, 0, 0, 0, stack_win->rect.width, stack_win->rect.height);
         }
 }
 
index d95ca4653dcff818b0d8cb19c82d8b49db373421..6061fd8d325bb5aa0f176c15aa9a2370646d3f28 100644 (file)
@@ -71,6 +71,9 @@ xcb_atom_t atoms[NUM_ATOMS];
 
 int num_screens = 0;
 
+/* The depth of the root screen (used e.g. for creating new pixmaps later) */
+uint8_t root_depth;
+
 /*
  * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb.
  * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop
@@ -261,7 +264,9 @@ int main(int argc, char *argv[], char *env[]) {
         xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
 
         /* Get the root window and set the event mask */
-        root = xcb_aux_get_screen(conn, screens)->root;
+        xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens);
+        root = root_screen->root;
+        root_depth = root_screen->root_depth;
 
         uint32_t mask = XCB_CW_EVENT_MASK;
         uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
index 3a3890f1635716b2709d26d1d87354cf65dd2920..02ce549646330e8547a23e0cf19cbcfc28d34244 100644 (file)
@@ -385,7 +385,8 @@ void leave_stack_mode(xcb_connection_t *conn, Container *container) {
 
         SLIST_REMOVE(&stack_wins, stack_win, Stack_Window, stack_windows);
 
-        xcb_free_gc(conn, stack_win->gc);
+        xcb_free_gc(conn, stack_win->pixmap.gc);
+        xcb_free_pixmap(conn, stack_win->pixmap.id);
         xcb_destroy_window(conn, stack_win->window);
 
         stack_win->rect.width = -1;
@@ -423,9 +424,11 @@ void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode)
                 struct Stack_Window *stack_win = &(container->stack_win);
                 stack_win->window = create_window(conn, rect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, mask, values);
 
-                /* Generate a graphics context for the titlebar */
-                stack_win->gc = xcb_generate_id(conn);
-                xcb_create_gc(conn, stack_win->gc, stack_win->window, 0, 0);
+                /* Initialize the entry for our cached pixmap. It will be
+                 * created as soon as it’s needed (see cached_pixmap_prepare). */
+                memset(&(stack_win->pixmap), 0, sizeof(struct Cached_Pixmap));
+                stack_win->pixmap.referred_rect = &stack_win->rect;
+                stack_win->pixmap.referred_drawable = stack_win->window;
 
                 stack_win->container = container;
 
index 4062f648e35254125bf448b90c044165e1e1af48..4ad69db1baf1b83fce4bee64b7c1929b3aa8e909 100644 (file)
--- a/src/xcb.c
+++ b/src/xcb.c
@@ -18,6 +18,7 @@
 #include <xcb/xcb.h>
 #include <xcb/xcb_keysyms.h>
 
+#include "i3.h"
 #include "util.h"
 #include "xcb.h"
 
@@ -259,3 +260,35 @@ void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window) {
         uint32_t values[] = { XCB_STACK_MODE_ABOVE };
         xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, values);
 }
+
+/*
+ *
+ * Prepares the given Cached_Pixmap for usage (checks whether the size of the
+ * object this pixmap is related to (e.g. a window) has changed and re-creates
+ * the pixmap if so).
+ *
+ */
+void cached_pixmap_prepare(xcb_connection_t *conn, struct Cached_Pixmap *pixmap) {
+        LOG("preparing pixmap\n");
+
+        /* If the Rect did not change, the pixmap does not need to be recreated */
+        if (memcmp(&(pixmap->rect), pixmap->referred_rect, sizeof(Rect)) == 0)
+                return;
+
+        memcpy(&(pixmap->rect), pixmap->referred_rect, sizeof(Rect));
+
+        if (pixmap->id == 0 || pixmap->gc == 0) {
+                LOG("Creating new pixmap...\n");
+                pixmap->id = xcb_generate_id(conn);
+                pixmap->gc = xcb_generate_id(conn);
+        } else {
+                LOG("Re-creating this pixmap...\n");
+                xcb_free_gc(conn, pixmap->gc);
+                xcb_free_pixmap(conn, pixmap->id);
+        }
+
+        xcb_create_pixmap(conn, root_depth, pixmap->id,
+                          pixmap->referred_drawable, pixmap->rect.width, pixmap->rect.height);
+
+        xcb_create_gc(conn, pixmap->gc, pixmap->id, 0, 0);
+}