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;
|
||||
};
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
|
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);
|
||||
|
||||
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;
|
||||
|
||||
|
|
33
src/xcb.c
33
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue