Speed up shadow generation for small windows

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-01-01 11:35:59 +00:00
parent 3686bf7a33
commit 428c24a6fa
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
7 changed files with 34 additions and 17 deletions

View File

@ -47,7 +47,7 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b)
}
xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel,
const double *shadow_sum, double opacity, int width, int height) {
double opacity, int width, int height) {
/*
* We classify shadows into 4 kinds of regions
* r = shadow radius
@ -62,6 +62,7 @@ xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel,
* height+r +-----+---------+-----+
*/
xcb_image_t *ximage;
const double *shadow_sum = kernel->rsum;
int d = kernel->size, r = d / 2;
int swidth = width + r * 2, sheight = height + r * 2;
@ -181,7 +182,7 @@ bool build_shadow(session_t *ps, double opacity, const int width, const int heig
xcb_gcontext_t gc = None;
shadow_image =
make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height);
make_shadow(ps->c, ps->gaussian_map, opacity, width, height);
if (!shadow_image) {
log_error("Failed to make shadow");
return false;

View File

@ -19,5 +19,5 @@ solid_picture(session_t *ps, bool argb, double a, double r, double g, double b);
void paint_all_new(session_t *ps, region_t *region, win *const t);
xcb_image_t *make_shadow(xcb_connection_t *c, const conv *kernel,
const double *shadow_sum, double opacity, int width, int height);
xcb_image_t *
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height);

View File

@ -531,8 +531,6 @@ typedef struct session {
/// Gaussian map of shadow.
conv *gaussian_map;
// for shadow precomputation
/// Pre-computed table for shadow.
double *shadow_sum;
/// A region in which shadow is not painted on.
region_t shadow_exclude_reg;

View File

@ -2640,7 +2640,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
.cshadow_picture = XCB_NONE,
.white_picture = XCB_NONE,
.gaussian_map = NULL,
.shadow_sum = NULL,
.refresh_rate = 0,
.refresh_intv = 0UL,

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <assert.h>
#include <math.h>
#include "kernel.h"
@ -28,9 +29,20 @@ double sum_kernel(const conv *map, int x, int y, int width, int height) {
if (yend > map->size)
yend = map->size;
assert(yend > 0 && xend > 0);
int d = map->size;
if (map->rsum) {
double v1 = xstart ? map->rsum[(yend - 1) * d + xstart - 1] : 0;
double v2 = ystart ? map->rsum[(ystart - 1) * d + xend - 1] : 0;
double v3 =
(xstart && ystart) ? map->rsum[(ystart - 1) * d + xstart - 1] : 0;
return map->rsum[(yend - 1) * d + xend - 1] - v1 - v2 + v3;
}
for (int yi = ystart; yi < yend; yi++) {
for (int xi = xstart; xi < xend; xi++) {
ret += map->data[yi * map->size + xi];
ret += map->data[yi * d + xi];
}
}
@ -65,6 +77,7 @@ conv *gaussian_kernel(double r) {
c = cvalloc(sizeof(conv) + size * size * sizeof(double));
c->size = size;
c->rsum = NULL;
t = 0.0;
for (int y = 0; y < size; y++) {
@ -86,13 +99,13 @@ conv *gaussian_kernel(double r) {
/// preprocess kernels to make shadow generation faster
/// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive
void shadow_preprocess(conv *map, double **shadow_sum) {
void shadow_preprocess(conv *map) {
const int d = map->size;
if (*shadow_sum)
free(*shadow_sum);
if (map->rsum)
free(map->rsum);
auto sum = *shadow_sum = ccalloc(d * d, double);
auto sum = map->rsum = ccalloc(d * d, double);
sum[0] = map->data[0];
for (int x = 1; x < d; x++) {

View File

@ -2,12 +2,14 @@
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <stdlib.h>
#include "compiler.h"
/// Code for generating convolution kernels
typedef struct conv {
int size;
double *rsum;
double data[];
} conv;
@ -21,4 +23,9 @@ conv *gaussian_kernel(double r);
/// preprocess kernels to make shadow generation faster
/// shadow_sum[x*d+y] is the sum of the kernel from (0, 0) to (x, y), inclusive
void shadow_preprocess(conv *map, double **shadow_sum);
void shadow_preprocess(conv *map);
static inline void free_conv(conv *k) {
free(k->rsum);
free(k);
}

View File

@ -451,7 +451,7 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) {
xcb_gcontext_t gc = XCB_NONE;
shadow_image =
make_shadow(ps->c, ps->gaussian_map, ps->shadow_sum, opacity, width, height);
make_shadow(ps->c, ps->gaussian_map, opacity, width, height);
if (!shadow_image) {
log_error("failed to make shadow");
return XCB_NONE;
@ -1058,7 +1058,7 @@ bool init_render(session_t *ps) {
}
ps->gaussian_map = gaussian_kernel(ps->o.shadow_radius);
shadow_preprocess(ps->gaussian_map, &ps->shadow_sum);
shadow_preprocess(ps->gaussian_map);
ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0);
ps->white_picture = solid_picture(ps, true, 1, 1, 1, 1);
@ -1116,8 +1116,7 @@ void deinit_render(session_t *ps) {
free_picture(ps->c, &ps->black_picture);
free_picture(ps->c, &ps->white_picture);
free(ps->shadow_sum);
free(ps->gaussian_map);
free_conv(ps->gaussian_map);
// Free other X resources
free_root_tile(ps);