new backends: blur interface update

To prepare for different blur methods, the blur interface of backends
has been splitted into two parts.

Now to use blur, a blur context must be created first; then, the blur
method should be called with the blur context created.

Updated the existing backends to the new interface. Also implemented
handling of the new blur options.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-06-09 19:25:34 +01:00
parent 1eba43f888
commit 67f0ec773a
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
8 changed files with 274 additions and 141 deletions

View File

@ -174,6 +174,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// We need to blur the bounding shape of the window
// (reg_paint = reg_bound \cap reg_damage)
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
ps->backend_blur_context,
&reg_paint, &reg_visible);
} else if (frame_transparent && ps->o.blur_background_frame) {
// Window itself is solid, we only need to blur the frame
@ -183,6 +184,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// make sure reg_blur \in reg_damage
pixman_region32_intersect(&reg_blur, &reg_blur, &reg_damage);
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
ps->backend_blur_context,
&reg_blur, &reg_visible);
pixman_region32_fini(&reg_blur);
}

View File

@ -130,8 +130,9 @@ struct backend_operations {
void (*fill)(backend_t *backend_data, struct color, const region_t *clip);
/// Blur a given region of the target.
bool (*blur)(backend_t *backend_data, double opacity, const region_t *reg_blur,
const region_t *reg_visible) attr_nonnull(1, 3, 4);
bool (*blur)(backend_t *backend_data, double opacity, void *blur_ctx,
const region_t *reg_blur, const region_t *reg_visible)
attr_nonnull(1, 3, 4, 5);
/// Present the back buffer onto the screen.
///
@ -209,6 +210,10 @@ struct backend_operations {
/// returned image should not affect the original image
void *(*copy)(backend_t *base, const void *image_data, const region_t *reg_visible);
/// Create a blur context that can be used to call `blur`
void *(*create_blur_context)(backend_t *base, enum blur_method, void *args);
void (*destroy_blur_context)(backend_t *base, void *ctx);
// =========== Hooks ============
/// Let the backend hook into the event handling queue
void (*set_ready_callback)(backend_t *, backend_ready_callback_t cb);

View File

@ -17,12 +17,38 @@
#include "string_utils.h"
#include "utils.h"
#include "backend/gl/gl_common.h"
#include "backend/backend_common.h"
#include "backend/gl/gl_common.h"
#define GLSL(version, ...) "#version " #version "\n" #__VA_ARGS__
#define QUOTE(...) #__VA_ARGS__
struct gl_blur_context {
enum blur_method method;
gl_blur_shader_t *blur_shader;
// Temporary textures used for blurring. They are always the same size as the
// target, so they are always big enough without resizing.
// Turns out calling glTexImage to resize is expensive, so we avoid that.
GLuint blur_texture[2];
// Temporary fbo used for blurring
GLuint blur_fbo;
int texture_width, texture_height;
int npasses;
};
static GLint glGetUniformLocationChecked(GLuint p, const char *name) {
auto ret = glGetUniformLocation(p, name);
if (ret < 0) {
log_error("Failed to get location of uniform '%s'. compton might not "
"work correctly.",
name);
}
return ret;
}
GLuint gl_create_shader(GLenum shader_type, const char *shader_str) {
log_trace("===\n%s\n===", shader_str);
@ -345,10 +371,44 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
/**
* Blur contents in a particular region.
*/
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blur,
const region_t *reg_visible) {
// Remainder: regions are in Xorg coordinates
struct gl_blur_context *bctx = ctx;
struct gl_data *gd = (void *)base;
if (gd->width != bctx->texture_width || gd->height != bctx->texture_height) {
// Resize the temporary textures used for blur in case the root
// size changed
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gd->width, gd->height, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL);
if (bctx->npasses > 1) {
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gd->width, gd->height, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL);
}
bctx->texture_width = gd->width;
bctx->texture_height = gd->height;
// XXX: do we need projection matrix for blur at all?
// Note: OpenGL matrices are column major
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)gd->width, 0, 0, 0},
{0, 2.0f / (GLfloat)gd->height, 0, 0},
{0, 0, 0, 0},
{-1, -1, 0, 1}};
// Update projection matrices in the blur shaders
for (int i = 0; i < bctx->npasses; i++) {
assert(bctx->blur_shader[i].prog);
glUseProgram(bctx->blur_shader[i].prog);
int pml = glGetUniformLocationChecked(bctx->blur_shader[i].prog,
"projection");
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
}
}
// Remainder: regions are in Xorg coordinates
const rect_t *extent = pixman_region32_extents((region_t *)reg_blur);
int width = extent->x2 - extent->x1, height = extent->y2 - extent->y1;
int dst_y = gd->height - extent->y2;
@ -356,9 +416,7 @@ bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
return true;
}
// these should be arguments
bool ret = false;
int nrects;
const rect_t *rects = pixman_region32_rectangles((region_t *)reg_blur, &nrects);
if (!nrects) {
@ -384,24 +442,24 @@ bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
int curr = 0;
glReadBuffer(GL_BACK);
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[0]);
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[0]);
// Copy the area to be blurred into tmp buffer
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extent->x1, dst_y, width, height);
for (int i = 0; i < gd->npasses; ++i) {
const gl_blur_shader_t *p = &gd->blur_shader[i];
for (int i = 0; i < bctx->npasses; ++i) {
const gl_blur_shader_t *p = &bctx->blur_shader[i];
assert(p->prog);
assert(gd->blur_texture[curr]);
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[curr]);
assert(bctx->blur_texture[curr]);
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[curr]);
glUseProgram(p->prog);
if (i < gd->npasses - 1) {
if (i < bctx->npasses - 1) {
// not last pass, draw into framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gd->blur_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, bctx->blur_fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, gd->blur_texture[!curr], 0);
GL_TEXTURE_2D, bctx->blur_texture[!curr], 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
log_error("Framebuffer attachment failed.");
@ -414,7 +472,7 @@ bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
glDrawBuffer(GL_BACK);
glUniform1f(p->unifm_opacity, (float)opacity);
}
if (i == gd->npasses - 1) {
if (i == bctx->npasses - 1) {
glUniform2f(p->orig_loc, 0, 0);
} else {
// For other than last pass, we are drawing to a texture, we
@ -460,16 +518,6 @@ end:
return ret;
}
static GLint glGetUniformLocationChecked(GLuint p, const char *name) {
auto ret = glGetUniformLocation(p, name);
if (ret < 0) {
log_error("Failed to get location of uniform '%s'. compton might not "
"work correctly.",
name);
}
return ret;
}
// clang-format off
const char *vertex_shader = GLSL(330,
uniform mat4 projection;
@ -520,32 +568,13 @@ void gl_resize(struct gl_data *gd, int width, int height) {
gd->height = height;
gd->width = width;
// XXX: do we need projection matrix at all?
// Note: OpenGL matrices are column major
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)width, 0, 0, 0},
{0, 2.0f / (GLfloat)height, 0, 0},
{0, 0, 0, 0},
{-1, -1, 0, 1}};
if (gd->npasses > 0) {
// Resize the temporary textures used for blur
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gd->width, gd->height, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL);
if (gd->npasses > 1) {
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gd->width, gd->height, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL);
}
// Update projection matrices in the blur shaders
for (int i = 0; i < gd->npasses; i++) {
assert(gd->blur_shader[i].prog);
glUseProgram(gd->blur_shader[i].prog);
int pml = glGetUniformLocationChecked(gd->blur_shader[i].prog,
"projection");
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
}
}
// Update projection matrix in the win shader
glUseProgram(gd->win_shader.prog);
int pml = glGetUniformLocationChecked(gd->win_shader.prog, "projection");
@ -660,16 +689,60 @@ void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visib
return new_img;
}
static inline void gl_free_blur_shader(gl_blur_shader_t *shader) {
if (shader->prog) {
glDeleteProgram(shader->prog);
}
shader->prog = 0;
}
void gl_destroy_blur_context(backend_t *base, void *ctx) {
struct gl_blur_context *bctx = ctx;
// Free GLSL shaders/programs
for (int i = 0; i < bctx->npasses; ++i) {
gl_free_blur_shader(&bctx->blur_shader[i]);
}
free(bctx->blur_shader);
glDeleteTextures(bctx->npasses > 1 ? 2 : 1, bctx->blur_texture);
if (bctx->npasses > 1) {
glDeleteFramebuffers(1, &bctx->blur_fbo);
}
free(bctx);
gl_check_err();
}
/**
* Initialize GL blur filters.
*/
static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nkernels) {
if (!nkernels) {
return true;
void *gl_create_blur_context(backend_t *base, enum blur_method method, void *args) {
bool success = true;
auto gd = (struct gl_data *)base;
struct conv **kernels;
auto ctx = cmalloc(struct gl_blur_context);
if (!method || method >= BLUR_METHOD_INVALID) {
ctx->method = BLUR_METHOD_NONE;
return ctx;
}
gd->npasses = nkernels;
gd->blur_shader = ccalloc(gd->npasses, gl_blur_shader_t);
ctx->method = BLUR_METHOD_KERNEL;
if (method == BLUR_METHOD_KERNEL) {
ctx->npasses = ((struct kernel_blur_args *)args)->kernel_count;
kernels = ((struct kernel_blur_args *)args)->kernels;
} else {
kernels = generate_blur_kernel(method, args, &ctx->npasses);
}
if (!ctx->npasses) {
ctx->method = BLUR_METHOD_NONE;
return ctx;
}
ctx->blur_shader = ccalloc(ctx->npasses, gl_blur_shader_t);
char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
// Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane
@ -701,7 +774,7 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nke
const char *shader_add = FRAG_SHADER_BLUR_ADD;
char *extension = strdup("");
for (int i = 0; i < nkernels; i++) {
for (int i = 0; i < ctx->npasses; i++) {
auto kern = kernels[i];
// Build shader
int width = kern->w, height = kern->h;
@ -726,7 +799,7 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nke
}
}
auto pass = gd->blur_shader + i;
auto pass = ctx->blur_shader + i;
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(extension) +
strlen(shader_body) + 10 /* sum */ +
1 /* null terminator */;
@ -742,7 +815,8 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nke
free(shader_str);
if (!pass->prog) {
log_error("Failed to create GLSL program.");
goto err;
success = false;
goto out;
}
glBindFragDataLocation(pass->prog, 0, "out_color");
@ -756,37 +830,46 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels, int nke
pass->in_texcoord = glGetAttribLocation(pass->prog, "in_texcoord");
pass->coord_loc = glGetAttribLocation(pass->prog, "coord");
}
free(extension);
// Texture size will be defined by gl_resize
glGenTextures(gd->npasses > 1 ? 2 : 1, gd->blur_texture);
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[0]);
glGenTextures(ctx->npasses > 1 ? 2 : 1, ctx->blur_texture);
glBindTexture(GL_TEXTURE_2D, ctx->blur_texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (gd->npasses > 1) {
glBindTexture(GL_TEXTURE_2D, gd->blur_texture[1]);
if (ctx->npasses > 1) {
glBindTexture(GL_TEXTURE_2D, ctx->blur_texture[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Generate FBO and textures when needed
glGenFramebuffers(1, &gd->blur_fbo);
if (!gd->blur_fbo) {
glGenFramebuffers(1, &ctx->blur_fbo);
if (!ctx->blur_fbo) {
log_error("Failed to generate framebuffer object for blur");
return false;
success = false;
goto out;
}
}
out:
if (method != BLUR_METHOD_KERNEL) {
// We generated the blur kernels, so we need to free them
for (int i = 0; i < ctx->npasses; i++) {
free(kernels[i]);
}
free(kernels);
}
if (!success) {
gl_destroy_blur_context(&gd->base, ctx);
ctx = NULL;
}
free(extension);
// Restore LC_NUMERIC
setlocale(LC_NUMERIC, lc_numeric_old);
free(lc_numeric_old);
gl_check_err();
return true;
err:
free(extension);
setlocale(LC_NUMERIC, lc_numeric_old);
free(lc_numeric_old);
return false;
return ctx;
}
// clang-format off
@ -828,9 +911,6 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
if (!gl_init_blur(gd, ps->o.blur_kerns, ps->o.blur_kernel_count)) {
return false;
}
gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag);
gd->fill_shader.in_coord_loc =
glGetAttribLocation(gd->fill_shader.prog, "in_coord");
@ -857,28 +937,9 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
return true;
}
static inline void gl_free_blur_shader(gl_blur_shader_t *shader) {
if (shader->prog) {
glDeleteProgram(shader->prog);
}
shader->prog = 0;
}
void gl_deinit(struct gl_data *gd) {
// Free GLSL shaders/programs
for (int i = 0; i < gd->npasses; ++i) {
gl_free_blur_shader(&gd->blur_shader[i]);
}
free(gd->blur_shader);
gl_free_prog_main(&gd->win_shader);
glDeleteTextures(gd->npasses > 1 ? 2 : 1, gd->blur_texture);
if (gd->npasses > 1) {
glDeleteFramebuffers(1, &gd->blur_fbo);
}
if (gd->logger) {
log_remove_target_tls(gd->logger);
gd->logger = NULL;

View File

@ -66,17 +66,8 @@ struct gl_data {
bool is_nvidia;
// Height and width of the viewport
int height, width;
int npasses;
gl_win_shader_t win_shader;
gl_fill_shader_t fill_shader;
gl_blur_shader_t *blur_shader;
// Temporary textures used for blurring. They are always the same size as the
// target, so they are always big enough without resizing.
// Turns out calling glTexImage to resize is expensive, so we avoid that.
GLuint blur_texture[2];
// Temporary fbo used for blurring
GLuint blur_fbo;
/// Called when an gl_texture is decoupled from the texture it refers. Returns
/// the decoupled user_data
@ -88,17 +79,6 @@ struct gl_data {
struct log_target *logger;
};
typedef struct {
/// Framebuffer used for blurring.
GLuint fbo;
/// Textures used for blurring.
GLuint textures[2];
/// Width of the textures.
int width;
/// Height of the textures.
int height;
} gl_blur_cache_t;
typedef struct session session_t;
#define GL_PROG_MAIN_INIT \
@ -128,8 +108,10 @@ void gl_release_image(backend_t *base, void *image_data);
void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible);
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
bool gl_blur(backend_t *base, double opacity, void *, const region_t *reg_blur,
const region_t *reg_visible);
void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
void gl_destroy_blur_context(backend_t *base, void *ctx);
bool gl_is_image_transparent(backend_t *base, void *image_data);
void gl_fill(backend_t *base, struct color, const region_t *clip);

View File

@ -472,6 +472,8 @@ struct backend_operations glx_ops = {
.buffer_age = glx_buffer_age,
.render_shadow = default_backend_render_shadow,
.fill = gl_fill,
.create_blur_context = gl_create_blur_context,
.destroy_blur_context = gl_destroy_blur_context,
.max_buffer_age = 5, // Why?
};

View File

@ -59,14 +59,17 @@ typedef struct _xrender_data {
/// Width and height of the target pixmap
int target_width, target_height;
xcb_special_event_t *present_event;
} xrender_data;
struct _xrender_blur_context {
enum blur_method method;
/// Blur kernels converted to X format
struct x_convolution_kernel **x_blur_kernel;
/// Number of blur kernels
int x_blur_kernel_count;
xcb_special_event_t *present_event;
} xrender_data;
};
struct _xrender_image_data {
// Pixmap that the client window draws to,
@ -123,8 +126,13 @@ static void fill(backend_t *base, struct color c, const region_t *clip) {
.height = to_u16_checked(extent->y2 - extent->y1)}});
}
static bool blur(backend_t *backend_data, double opacity, const region_t *reg_blur,
const region_t *reg_visible) {
static bool blur(backend_t *backend_data, double opacity, void *ctx_,
const region_t *reg_blur, const region_t *reg_visible) {
struct _xrender_blur_context *bctx = ctx_;
if (bctx->method == BLUR_METHOD_NONE) {
return true;
}
struct _xrender_data *xd = (void *)backend_data;
xcb_connection_t *c = xd->base.c;
region_t reg_op;
@ -178,17 +186,17 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_bl
// For 1 pass, we do
// back -(pass 1)-> tmp0 -(copy)-> target_buffer
int i;
for (i = 0; i < xd->x_blur_kernel_count; i++) {
for (i = 0; i < bctx->x_blur_kernel_count; i++) {
// Copy from source picture to destination. The filter must
// be applied on source picture, to get the nearby pixels outside the
// window.
// TODO cache converted blur_kerns
xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)),
filter,
to_u32_checked(xd->x_blur_kernel[i]->size),
xd->x_blur_kernel[i]->kernel);
to_u32_checked(bctx->x_blur_kernel[i]->size),
bctx->x_blur_kernel[i]->kernel);
if (i < xd->x_blur_kernel_count - 1 || i == 0) {
if (i < bctx->x_blur_kernel_count - 1 || i == 0) {
// This is not the last pass, or this is the first pass
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict,
XCB_NONE, dst_pict, src_x, src_y, 0, 0, 0, 0,
@ -273,10 +281,6 @@ static void deinit(backend_t *backend_data) {
xcb_render_free_picture(xd->base.c, xd->back[i]);
xcb_free_pixmap(xd->base.c, xd->back_pixmap[i]);
}
for (int i = 0; i < xd->x_blur_kernel_count; i++) {
free(xd->x_blur_kernel[i]);
}
free(xd->x_blur_kernel);
if (xd->present_event) {
xcb_unregister_for_special_event(xd->base.c, xd->present_event);
}
@ -468,6 +472,50 @@ static void *copy(backend_t *base, const void *image, const region_t *reg) {
return new_img;
}
void *create_blur_context(backend_t *base, enum blur_method method, void *args) {
auto ret = cmalloc(struct _xrender_blur_context);
if (!method || method >= BLUR_METHOD_INVALID) {
ret->method = BLUR_METHOD_NONE;
return ret;
}
ret->method = BLUR_METHOD_KERNEL;
struct conv **kernels;
int kernel_count;
if (method == BLUR_METHOD_KERNEL) {
kernels = ((struct kernel_blur_args *)args)->kernels;
kernel_count = ((struct kernel_blur_args *)args)->kernel_count;
} else {
kernels = generate_blur_kernel(method, args, &kernel_count);
}
ret->x_blur_kernel = ccalloc(kernel_count, struct x_convolution_kernel *);
for (int i = 0; i < kernel_count; i++) {
int center = kernels[i]->h * kernels[i]->w / 2;
x_create_convolution_kernel(kernels[i], kernels[i]->data[center],
&ret->x_blur_kernel[i]);
}
ret->x_blur_kernel_count = kernel_count;
if (method != BLUR_METHOD_KERNEL) {
// Kernels generated by generate_blur_kernel, so we need to free them.
for (int i = 0; i < kernel_count; i++) {
free(kernels[i]);
}
free(kernels);
}
return ret;
}
void destroy_blur_context(backend_t *base, void *ctx_) {
struct _xrender_blur_context *ctx = ctx_;
for (int i = 0; i < ctx->x_blur_kernel_count; i++) {
free(ctx->x_blur_kernel[i]);
}
free(ctx->x_blur_kernel);
free(ctx);
}
backend_t *backend_xrender_init(session_t *ps) {
auto xd = ccalloc(1, struct _xrender_data);
init_backend_base(&xd->base, ps);
@ -550,15 +598,6 @@ backend_t *backend_xrender_init(session_t *ps) {
xd->root_pict = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, root_pixmap, 0, NULL);
}
xd->x_blur_kernel = ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *);
for (int i = 0; i < ps->o.blur_kernel_count; i++) {
int center = ps->o.blur_kerns[i]->h * ps->o.blur_kerns[i]->w / 2;
x_create_convolution_kernel(ps->o.blur_kerns[i],
ps->o.blur_kerns[i]->data[center],
&xd->x_blur_kernel[i]);
}
xd->x_blur_kernel_count = ps->o.blur_kernel_count;
return &xd->base;
err:
deinit(&xd->base);
@ -583,6 +622,8 @@ struct backend_operations xrender_ops = {
.image_op = image_op,
.copy = copy,
.create_blur_context = create_blur_context,
.destroy_blur_context = destroy_blur_context,
};
// vim: set noet sw=8 ts=8:

View File

@ -143,6 +143,9 @@ typedef struct session {
ev_signal int_signal;
/// backend data
backend_t *backend_data;
/// backend blur context
void *backend_blur_context;
/// graphic drivers used
enum driver drivers;
/// libev mainloop
struct ev_loop *loop;

View File

@ -29,9 +29,9 @@
#include <test.h>
#include "common.h"
#include "config.h"
#include "compiler.h"
#include "compton.h"
#include "config.h"
#include "err.h"
#include "kernel.h"
#ifdef CONFIG_OPENGL
@ -666,11 +666,43 @@ static void destroy_backend(session_t *ps) {
if (ps->backend_data) {
// deinit backend
ps->backend_data->ops->destroy_blur_context(ps->backend_data,
ps->backend_blur_context);
ps->backend_blur_context = NULL;
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data = NULL;
}
}
static bool initialize_blur(session_t *ps) {
struct kernel_blur_args kargs;
struct gaussian_blur_args gargs;
struct box_blur_args bargs;
void *args = NULL;
switch (ps->o.blur_method) {
case BLUR_METHOD_BOX:
bargs.size = ps->o.blur_radius;
args = (void *)&bargs;
break;
case BLUR_METHOD_KERNEL:
kargs.kernel_count = ps->o.blur_kernel_count;
kargs.kernels = ps->o.blur_kerns;
args = (void *)&kargs;
break;
case BLUR_METHOD_GAUSSIAN:
gargs.size = ps->o.blur_radius;
gargs.deviation = ps->o.blur_deviation;
args = (void *)&gargs;
break;
default: return true;
}
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
ps->backend_data, ps->o.blur_method, args);
return ps->backend_blur_context != NULL;
}
/// Init the backend and bind all the window pixmap to backend images
static bool initialize_backend(session_t *ps) {
if (ps->o.experimental_backends) {
@ -679,14 +711,20 @@ static bool initialize_backend(session_t *ps) {
ps->backend_data = backend_list[ps->o.backend]->init(ps);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
ps->quit = true;
ev_break(ps->loop, EVBREAK_ALL);
quit_compton(ps);
return false;
}
ps->backend_data->ops = backend_list[ps->o.backend];
// window_stack shouldn't include window that's not in the hash table at
// this point. Since there cannot be any fading windows.
if (!initialize_blur(ps)) {
log_fatal("Failed to prepare for background blur, aborting...");
quit_compton(ps);
return false;
}
// window_stack shouldn't include window that's
// not in the hash table at this point. Since
// there cannot be any fading windows.
HASH_ITER2(ps->windows, _w) {
if (!_w->managed) {
continue;
@ -874,8 +912,7 @@ static bool register_cm(session_t *ps) {
{
auto pid = getpid();
xcb_change_property(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL,
32, 1, &pid);
ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
}
// Set COMPTON_VERSION