From 5a3dfbc064d0a284ad234f9f85fe324e73f3e3eb Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Sat, 29 Sep 2012 13:15:09 +0800 Subject: [PATCH] Improvement: Split shadow_pict to shadow_pict & shadow_alpha_pict Split w->shadow_pict to w->shadow_pict and w->shadow_alpha_pict, so that the whole w->shadow_pict need not to be rebuild on shadow opacity change. This greatly reduces CPU usage of compton when a window with shadow is fading. (My test shows the CPU usage of compton process dropped from 1.15% to 0.35% when constantly fading in and out a window.) It uses a rather painful and slow method in shadow_picture() to get around the limitation of PictStandardA8 to make colored shadows work. I wonder if there's a better approach. - Merge variables gsize and cgsize as they seemingly represent the same thing. --- src/compton.c | 100 ++++++++++++++++++++++++++++++-------------------- src/compton.h | 5 ++- 2 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/compton.c b/src/compton.c index d462180..7beafd4 100644 --- a/src/compton.c +++ b/src/compton.c @@ -384,11 +384,10 @@ make_shadow(Display *dpy, double opacity, int width, int height) { XImage *ximage; unsigned char *data; - int gsize = gaussian_map->size; int ylimit, xlimit; - int swidth = width + gsize; - int sheight = height + gsize; - int center = gsize / 2; + int swidth = width + cgsize; + int sheight = height + cgsize; + int center = cgsize / 2; int x, y; unsigned char d; int x_diff; @@ -434,10 +433,10 @@ make_shadow(Display *dpy, double opacity, * corners */ - ylimit = gsize; + ylimit = cgsize; if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2; - xlimit = gsize; + xlimit = cgsize; if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2; for (y = 0; y < ylimit; y++) { @@ -460,7 +459,7 @@ make_shadow(Display *dpy, double opacity, * top/bottom */ - x_diff = swidth - (gsize * 2); + x_diff = swidth - (cgsize * 2); if (x_diff > 0 && ylimit > 0) { for (y = 0; y < ylimit; y++) { if (ylimit == cgsize) { @@ -469,8 +468,8 @@ make_shadow(Display *dpy, double opacity, d = sum_gaussian(gaussian_map, opacity, center, y - center, width, height); } - memset(&data[y * swidth + gsize], d, x_diff); - memset(&data[(sheight - y - 1) * swidth + gsize], d, x_diff); + memset(&data[y * swidth + cgsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + cgsize], d, x_diff); } } @@ -485,7 +484,7 @@ make_shadow(Display *dpy, double opacity, d = sum_gaussian(gaussian_map, opacity, x - center, center, width, height); } - for (y = gsize; y < sheight - gsize; y++) { + for (y = cgsize; y < sheight - cgsize; y++) { data[y * swidth + x] = d; data[y * swidth + (swidth - x - 1)] = d; } @@ -512,48 +511,62 @@ make_shadow(Display *dpy, double opacity, static Picture shadow_picture(Display *dpy, double opacity, int width, int height) { - XImage *shadow_image; - Pixmap shadow_pixmap; - Picture shadow_picture; - GC gc; + XImage *shadow_image = NULL; + Pixmap shadow_pixmap = None, shadow_pixmap_argb = None; + Picture shadow_picture = None, shadow_picture_argb = None; + GC gc = None; shadow_image = make_shadow(dpy, opacity, width, height); - if (!shadow_image) return None; + if (!shadow_image) + return None; shadow_pixmap = XCreatePixmap(dpy, root, shadow_image->width, shadow_image->height, 8); + shadow_pixmap_argb = XCreatePixmap(dpy, root, + shadow_image->width, shadow_image->height, 32); - if (!shadow_pixmap) { - XDestroyImage(shadow_image); - return None; - } + if (!shadow_pixmap || !shadow_pixmap_argb) + goto shadow_picture_err; shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap, XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0); - - if (!shadow_picture) { - XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - return None; - } + shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb, + XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0); + if (!shadow_picture || !shadow_picture_argb) + goto shadow_picture_err; gc = XCreateGC(dpy, shadow_pixmap, 0, 0); - if (!gc) { - XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - XRenderFreePicture(dpy, shadow_picture); - return None; - } + if (!gc) + goto shadow_picture_err; - XPutImage( - dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, + XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, shadow_image->width, shadow_image->height); + XRenderComposite(dpy, PictOpSrc, cshadow_picture, shadow_picture, + shadow_picture_argb, 0, 0, 0, 0, 0, 0, + shadow_image->width, shadow_image->height); XFreeGC(dpy, gc); XDestroyImage(shadow_image); XFreePixmap(dpy, shadow_pixmap); + XFreePixmap(dpy, shadow_pixmap_argb); + XRenderFreePicture(dpy, shadow_picture); - return shadow_picture; + return shadow_picture_argb; + +shadow_picture_err: + if (shadow_image) + XDestroyImage(shadow_image); + if (shadow_pixmap) + XFreePixmap(dpy, shadow_pixmap); + if (shadow_pixmap_argb) + XFreePixmap(dpy, shadow_pixmap_argb); + if (shadow_picture) + XRenderFreePicture(dpy, shadow_picture); + if (shadow_picture_argb) + XRenderFreePicture(dpy, shadow_picture_argb); + if (gc) + XFreeGC(dpy, gc); + return None; } static Picture @@ -1276,12 +1289,18 @@ paint_preprocess(Display *dpy, win *list) { if (w->flags & WFLAG_SIZE_CHANGE) free_picture(dpy, &w->shadow_pict); - if (w->shadow - && (!w->shadow_pict - || w->shadow_opacity != w->shadow_opacity_cur)) { - free_picture(dpy, &w->shadow_pict); - w->shadow_pict = shadow_picture(dpy, w->shadow_opacity, + if (w->shadow && !w->shadow_pict) { + w->shadow_pict = shadow_picture(dpy, 1, w->widthb, w->heightb); + } + + // Rebuild shadow_alpha_pict if necessary + if (w->shadow + && (!w->shadow_alpha_pict + || w->shadow_opacity != w->shadow_opacity_cur)) { + free_picture(dpy, &w->shadow_alpha_pict); + w->shadow_alpha_pict = solid_picture( + dpy, False, w->shadow_opacity, 0, 0, 0); w->shadow_opacity_cur = w->shadow_opacity; } @@ -1359,7 +1378,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // Painting shadow if (w->shadow) { XRenderComposite( - dpy, PictOpOver, cshadow_picture, w->shadow_pict, + dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, root_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -1942,6 +1961,7 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->shadow_opacity = 0.0; new->shadow_opacity_cur = 0.0; new->shadow_pict = None; + new->shadow_alpha_pict = None; new->shadow_dx = 0; new->shadow_dy = 0; new->shadow_width = 0; diff --git a/src/compton.h b/src/compton.h index 51118e8..f3c3236 100644 --- a/src/compton.h +++ b/src/compton.h @@ -228,9 +228,10 @@ typedef struct _win { int shadow_width; /// Height of shadow. Affected by window size and commandline argument. int shadow_height; - /// Alpha mask Picture to render shadow. Affected by window size and - /// shadow opacity. + /// Picture to render shadow. Affected by window size. Picture shadow_pict; + /// Alpha mask Picture to render shadow. Affected by shadow opacity. + Picture shadow_alpha_pict; // Dim-related members /// Whether the window is to be dimmed.