Speed up shadow generation for small windows
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
3686bf7a33
commit
428c24a6fa
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
23
src/kernel.c
23
src/kernel.c
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue