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.
This commit is contained in:
Richard Grenville 2012-09-29 13:15:09 +08:00
parent 9139d038c2
commit 5a3dfbc064
2 changed files with 63 additions and 42 deletions

View File

@ -384,11 +384,10 @@ make_shadow(Display *dpy, double opacity,
int width, int height) { int width, int height) {
XImage *ximage; XImage *ximage;
unsigned char *data; unsigned char *data;
int gsize = gaussian_map->size;
int ylimit, xlimit; int ylimit, xlimit;
int swidth = width + gsize; int swidth = width + cgsize;
int sheight = height + gsize; int sheight = height + cgsize;
int center = gsize / 2; int center = cgsize / 2;
int x, y; int x, y;
unsigned char d; unsigned char d;
int x_diff; int x_diff;
@ -434,10 +433,10 @@ make_shadow(Display *dpy, double opacity,
* corners * corners
*/ */
ylimit = gsize; ylimit = cgsize;
if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2; if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2;
xlimit = gsize; xlimit = cgsize;
if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2; if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2;
for (y = 0; y < ylimit; y++) { for (y = 0; y < ylimit; y++) {
@ -460,7 +459,7 @@ make_shadow(Display *dpy, double opacity,
* top/bottom * top/bottom
*/ */
x_diff = swidth - (gsize * 2); x_diff = swidth - (cgsize * 2);
if (x_diff > 0 && ylimit > 0) { if (x_diff > 0 && ylimit > 0) {
for (y = 0; y < ylimit; y++) { for (y = 0; y < ylimit; y++) {
if (ylimit == cgsize) { if (ylimit == cgsize) {
@ -469,8 +468,8 @@ make_shadow(Display *dpy, double opacity,
d = sum_gaussian(gaussian_map, d = sum_gaussian(gaussian_map,
opacity, center, y - center, width, height); opacity, center, y - center, width, height);
} }
memset(&data[y * swidth + gsize], d, x_diff); memset(&data[y * swidth + cgsize], d, x_diff);
memset(&data[(sheight - y - 1) * swidth + gsize], 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, d = sum_gaussian(gaussian_map,
opacity, x - center, center, width, height); 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 + x] = d;
data[y * swidth + (swidth - x - 1)] = d; data[y * swidth + (swidth - x - 1)] = d;
} }
@ -512,48 +511,62 @@ make_shadow(Display *dpy, double opacity,
static Picture static Picture
shadow_picture(Display *dpy, double opacity, int width, int height) { shadow_picture(Display *dpy, double opacity, int width, int height) {
XImage *shadow_image; XImage *shadow_image = NULL;
Pixmap shadow_pixmap; Pixmap shadow_pixmap = None, shadow_pixmap_argb = None;
Picture shadow_picture; Picture shadow_picture = None, shadow_picture_argb = None;
GC gc; GC gc = None;
shadow_image = make_shadow(dpy, opacity, width, height); shadow_image = make_shadow(dpy, opacity, width, height);
if (!shadow_image) return None; if (!shadow_image)
return None;
shadow_pixmap = XCreatePixmap(dpy, root, shadow_pixmap = XCreatePixmap(dpy, root,
shadow_image->width, shadow_image->height, 8); shadow_image->width, shadow_image->height, 8);
shadow_pixmap_argb = XCreatePixmap(dpy, root,
shadow_image->width, shadow_image->height, 32);
if (!shadow_pixmap) { if (!shadow_pixmap || !shadow_pixmap_argb)
XDestroyImage(shadow_image); goto shadow_picture_err;
return None;
}
shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap, shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap,
XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0); XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0);
shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb,
if (!shadow_picture) { XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0);
XDestroyImage(shadow_image); if (!shadow_picture || !shadow_picture_argb)
XFreePixmap(dpy, shadow_pixmap); goto shadow_picture_err;
return None;
}
gc = XCreateGC(dpy, shadow_pixmap, 0, 0); gc = XCreateGC(dpy, shadow_pixmap, 0, 0);
if (!gc) { if (!gc)
XDestroyImage(shadow_image); goto shadow_picture_err;
XFreePixmap(dpy, shadow_pixmap);
XRenderFreePicture(dpy, shadow_picture);
return None;
}
XPutImage( XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0,
dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0,
shadow_image->width, shadow_image->height); 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); XFreeGC(dpy, gc);
XDestroyImage(shadow_image); XDestroyImage(shadow_image);
XFreePixmap(dpy, shadow_pixmap); 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 static Picture
@ -1276,12 +1289,18 @@ paint_preprocess(Display *dpy, win *list) {
if (w->flags & WFLAG_SIZE_CHANGE) if (w->flags & WFLAG_SIZE_CHANGE)
free_picture(dpy, &w->shadow_pict); free_picture(dpy, &w->shadow_pict);
if (w->shadow if (w->shadow && !w->shadow_pict) {
&& (!w->shadow_pict w->shadow_pict = shadow_picture(dpy, 1,
|| w->shadow_opacity != w->shadow_opacity_cur)) {
free_picture(dpy, &w->shadow_pict);
w->shadow_pict = shadow_picture(dpy, w->shadow_opacity,
w->widthb, w->heightb); 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; w->shadow_opacity_cur = w->shadow_opacity;
} }
@ -1359,7 +1378,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
// Painting shadow // Painting shadow
if (w->shadow) { if (w->shadow) {
XRenderComposite( XRenderComposite(
dpy, PictOpOver, cshadow_picture, w->shadow_pict, dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict,
root_buffer, 0, 0, 0, 0, root_buffer, 0, 0, 0, 0,
w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height); 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 = 0.0;
new->shadow_opacity_cur = 0.0; new->shadow_opacity_cur = 0.0;
new->shadow_pict = None; new->shadow_pict = None;
new->shadow_alpha_pict = None;
new->shadow_dx = 0; new->shadow_dx = 0;
new->shadow_dy = 0; new->shadow_dy = 0;
new->shadow_width = 0; new->shadow_width = 0;

View File

@ -228,9 +228,10 @@ typedef struct _win {
int shadow_width; int shadow_width;
/// Height of shadow. Affected by window size and commandline argument. /// Height of shadow. Affected by window size and commandline argument.
int shadow_height; int shadow_height;
/// Alpha mask Picture to render shadow. Affected by window size and /// Picture to render shadow. Affected by window size.
/// shadow opacity.
Picture shadow_pict; Picture shadow_pict;
/// Alpha mask Picture to render shadow. Affected by shadow opacity.
Picture shadow_alpha_pict;
// Dim-related members // Dim-related members
/// Whether the window is to be dimmed. /// Whether the window is to be dimmed.