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:
parent
0434b6ea3d
commit
5b51c8c6f0
|
@ -101,6 +101,22 @@ struct Colorpixel {
|
||||||
SLIST_ENTRY(Colorpixel) colorpixels;
|
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
|
* Contains data for the windows needed to draw the titlebars on in stacking
|
||||||
* mode
|
* mode
|
||||||
|
@ -108,7 +124,7 @@ struct Colorpixel {
|
||||||
*/
|
*/
|
||||||
struct Stack_Window {
|
struct Stack_Window {
|
||||||
xcb_window_t window;
|
xcb_window_t window;
|
||||||
xcb_gcontext_t gc;
|
struct Cached_Pixmap pixmap;
|
||||||
Rect rect;
|
Rect rect;
|
||||||
|
|
||||||
/** Backpointer to the container this stack window is in */
|
/** Backpointer to the container this stack window is in */
|
||||||
|
|
|
@ -30,6 +30,7 @@ extern TAILQ_HEAD(assignments_head, Assignment) assignments;
|
||||||
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
||||||
extern xcb_event_handlers_t evenths;
|
extern xcb_event_handlers_t evenths;
|
||||||
extern int num_screens;
|
extern int num_screens;
|
||||||
|
extern uint8_t root_depth;
|
||||||
extern xcb_atom_t atoms[NUM_ATOMS];
|
extern xcb_atom_t atoms[NUM_ATOMS];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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);
|
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
|
#endif
|
||||||
|
|
|
@ -362,6 +362,9 @@ void render_container(xcb_connection_t *conn, Container *container) {
|
||||||
xcb_configure_window(conn, stack_win->window, mask, values);
|
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 */
|
/* Render the decorations of all clients */
|
||||||
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
||||||
/* If the client is in fullscreen mode, it does not get reconfigured */
|
/* 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;
|
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ xcb_atom_t atoms[NUM_ATOMS];
|
||||||
|
|
||||||
int num_screens = 0;
|
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.
|
* 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
|
* 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);
|
xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
|
||||||
|
|
||||||
/* Get the root window and set the event mask */
|
/* 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 mask = XCB_CW_EVENT_MASK;
|
||||||
uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
||||||
|
|
11
src/util.c
11
src/util.c
|
@ -385,7 +385,8 @@ void leave_stack_mode(xcb_connection_t *conn, Container *container) {
|
||||||
|
|
||||||
SLIST_REMOVE(&stack_wins, stack_win, Stack_Window, stack_windows);
|
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);
|
xcb_destroy_window(conn, stack_win->window);
|
||||||
|
|
||||||
stack_win->rect.width = -1;
|
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);
|
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);
|
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 */
|
/* Initialize the entry for our cached pixmap. It will be
|
||||||
stack_win->gc = xcb_generate_id(conn);
|
* created as soon as it’s needed (see cached_pixmap_prepare). */
|
||||||
xcb_create_gc(conn, stack_win->gc, stack_win->window, 0, 0);
|
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;
|
stack_win->container = container;
|
||||||
|
|
||||||
|
|
33
src/xcb.c
33
src/xcb.c
|
@ -18,6 +18,7 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
|
|
||||||
|
#include "i3.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xcb.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 };
|
uint32_t values[] = { XCB_STACK_MODE_ABOVE };
|
||||||
xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue