optimization: Render on pixmaps and copy the result on Stack_Wins

This should speed up the rendering of Stack_Wins with many window
decorations and it should considerably reduce flicker.
This commit is contained in:
Michael Stapelberg
2009-07-17 18:32:40 +02:00
parent 0434b6ea3d
commit 5b51c8c6f0
7 changed files with 80 additions and 7 deletions

View 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);
}
}

View 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 |

View 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 its 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;

View File

@ -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);
}