Compare commits

...

9 Commits

Author SHA1 Message Date
Neal Gompa (ニール・ゴンパ) c703a695e6
Merge 7442b4103b into 1d94af4140 2024-04-09 16:32:45 +02:00
Yuxuan Shui 1d94af4140
backend: document my confusion
See e3e73d7fc1

The reason composing worked without using the mask image is because the
paint region already carves the relevant parts of shaped windows.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 17:57:08 +01:00
Yuxuan Shui e5210aea7b
flake: add a dev shell that has frame pointers
Helps tremendously with getting stack trace from ASan, etc.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 09:42:51 +01:00
Yuxuan Shui c51d446854
backend: move pixmap ownership management out of the backends
Caller of `bind_pixmap` generally knows if the pixmap is owned or not,
they are fully able to decide if the pixmap should be freed, so let them
do it.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 09:14:59 +01:00
Yuxuan Shui be78557dae
win: fix leak of damaged regions of windows
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 07:52:37 +01:00
Yuxuan Shui e3e73d7fc1
backend: use window mask for composing
Don't know why this has been working so far... Shaped windows shouldn't
have been rendering correctly. Probably the mask was bound to the
correct texture unit by accident...

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-08 00:24:47 +01:00
Yuxuan Shui 26414ddd38
backend: gl: fix opacity not being applied for single pass kernel blur
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-06 20:18:23 +01:00
Yuxuan Shui 70a703df43
backend: gl: fix gl_present not using the correct texture unit
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2024-04-06 02:38:11 +01:00
Neal Gompa 7442b4103b picom.desktop: Hide from menus by default
Like the Compton desktop file, this desktop entry should be marked
as hidden by default because it's intended to be configured and
started as part of the X11 environment.
2023-12-17 14:49:26 -05:00
16 changed files with 150 additions and 136 deletions

View File

@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@ -25,11 +25,11 @@
]
},
"locked": {
"lastModified": 1703887061,
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
@ -41,11 +41,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1705856552,
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
"lastModified": 1712517181,
"narHash": "sha256-NfHaSxL89kX39s1V1/EnnIqBX8LXcc/7ow5fzfCwPrM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
"rev": "6507feebbd146188300681ca26bac5da3c12b9f1",
"type": "github"
},
"original": {

View File

@ -38,15 +38,17 @@
inherit system overlays;
config.allowBroken = true;
};
profilePkgs = import nixpkgs {
inherit system;
overlays = overlays ++ [
(final: prev: {
stdenv = prev.withCFlags "-fno-omit-frame-pointer" prev.stdenv;
})
];
};
overlays = [overlay];
in rec {
inherit
overlay
overlays
;
defaultPackage = pkgs.picom;
devShells.default = defaultPackage.overrideAttrs (o: {
mkDevShell = p: p.overrideAttrs (o: {
nativeBuildInputs = o.nativeBuildInputs ++ (with pkgs; [
clang-tools_17
llvmPackages_17.clang-unwrapped.python
@ -59,8 +61,20 @@
export LD_LIBRARY_PATH+=":/run/opengl-driver/lib"
'';
});
in rec {
inherit
overlay
overlays
;
defaultPackage = pkgs.picom;
devShells.default = mkDevShell defaultPackage;
devShells.useClang = devShells.default.override {
inherit (pkgs.llvmPackages_17) stdenv;
};
# build picom and all dependencies with frame pointer, making profiling/debugging easier.
# WARNING! many many rebuilds
devShells.useClangProfile = (mkDevShell profilePkgs.picom).override {
stdenv = profilePkgs.withCFlags "-fno-omit-frame-pointer" profilePkgs.llvmPackages_17.stdenv;
};
});
}

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Version=1.0
Type=Application
NoDisplay=false
NoDisplay=true
Name=picom
GenericName=X compositor
Comment=An X compositor

View File

@ -431,11 +431,22 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
pixman_region32_subtract(&reg_shadow_clip, &reg_shadow_clip, &reg_bound);
}
if (w->mask_image) {
// We are now going to compose the main window body, so
// we need to set the mask image to be non-inverted
ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_INVERTED, w->mask_image,
(bool[]){false});
}
// Draw window on target
if (w->frame_opacity == 1) {
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
window_coord, NULL, window_coord,
&reg_paint_in_bound, &reg_visible);
// We use both reg_paint_in_bound and mask image, which is
// probably no strictly necessary. Even for shaped windows, they
// should be the same.
ps->backend_data->ops->compose(
ps->backend_data, w->win_image, window_coord, w->mask_image,
window_coord, &reg_paint_in_bound, &reg_visible);
} else {
// For window image processing, we don't have to limit the process
// region to damage for correctness. (see <damager-note> for
@ -473,10 +484,12 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, &reg_frame,
&reg_visible_local, (double[]){w->frame_opacity});
pixman_region32_fini(&reg_frame);
ps->backend_data->ops->compose(ps->backend_data, new_img,
window_coord, NULL, window_coord,
&reg_paint_in_bound, &reg_visible);
ps->backend_data->ops->release_image(ps->backend_data, new_img);
ps->backend_data->ops->compose(
ps->backend_data, new_img, window_coord, w->mask_image,
window_coord, &reg_paint_in_bound, &reg_visible);
auto pixmap =
ps->backend_data->ops->release_image(ps->backend_data, new_img);
CHECK(pixmap == XCB_NONE);
pixman_region32_fini(&reg_visible_local);
pixman_region32_fini(&reg_bound_local);
}

View File

@ -208,13 +208,11 @@ struct backend_operations {
* @param backend_data backend data
* @param pixmap X pixmap to bind
* @param fmt information of the pixmap's visual
* @param owned whether the ownership of the pixmap is transferred to the
* backend.
* @return backend specific image handle for the pixmap. May be
* NULL.
*/
image_handle (*bind_pixmap)(backend_t *backend_data, xcb_pixmap_t pixmap,
struct xvisual_info fmt, bool owned);
struct xvisual_info fmt);
/// Create a shadow context for rendering shadows with radius `radius`.
/// Default implementation: default_create_shadow_context
@ -268,7 +266,10 @@ struct backend_operations {
/// Free resources associated with an image data structure
///
/// @param image the image to be released, cannot be NULL.
void (*release_image)(backend_t *backend_data, image_handle image) attr_nonnull(1, 2);
/// @return if this image is created by `bind_pixmap`, the X pixmap; 0
/// otherwise.
xcb_pixmap_t (*release_image)(backend_t *backend_data, image_handle image)
attr_nonnull(1, 2);
/// Create a shader object from a shader source.
///

View File

@ -309,9 +309,12 @@ image_handle default_render_shadow(backend_t *backend_data, int width, int heigh
auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32);
auto ret = backend_data->ops->bind_pixmap(
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
backend_data, shadow, x_get_visual_info(backend_data->c, visual));
x_free_picture(backend_data->c, pict);
x_free_picture(backend_data->c, shadow_pixel);
if (!ret) {
xcb_free_pixmap(backend_data->c->c, shadow);
}
return ret;
}
@ -326,7 +329,8 @@ backend_render_shadow_from_mask(backend_t *backend_data, int width, int height,
pixman_region32_fini(&reg);
auto shadow = backend_data->ops->shadow_from_mask(backend_data, mask, sctx, color);
backend_data->ops->release_image(backend_data, mask);
auto pixmap = backend_data->ops->release_image(backend_data, mask);
CHECK(pixmap == XCB_NONE);
return shadow;
}

View File

@ -85,8 +85,8 @@ bool dummy_blur(struct backend_base *backend_data attr_unused, double opacity at
return true;
}
image_handle dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
struct xvisual_info fmt, bool owned) {
image_handle
dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap, struct xvisual_info fmt) {
auto dummy = (struct dummy_data *)base;
struct dummy_image *img = NULL;
HASH_FIND_INT(dummy->images, &pixmap, img);
@ -100,28 +100,27 @@ image_handle dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
img->transparent = fmt.alpha_size != 0;
img->refcount = ccalloc(1, int);
*img->refcount = 1;
img->owned = owned;
HASH_ADD_INT(dummy->images, pixmap, img);
return (image_handle)img;
}
void dummy_release_image(backend_t *base, image_handle image) {
xcb_pixmap_t dummy_release_image(backend_t *base, image_handle image) {
auto dummy = (struct dummy_data *)base;
if ((struct backend_image *)image == &dummy->mask) {
return;
return XCB_NONE;
}
auto img = (struct dummy_image *)image;
xcb_pixmap_t pixmap = XCB_NONE;
assert(*img->refcount > 0);
(*img->refcount)--;
if (*img->refcount == 0) {
HASH_DEL(dummy->images, img);
free(img->refcount);
if (img->owned) {
xcb_free_pixmap(base->c->c, img->pixmap);
}
pixmap = img->pixmap;
free(img);
}
return pixmap;
}
bool dummy_is_image_transparent(struct backend_base *base, image_handle image) {

View File

@ -626,14 +626,14 @@ bool gl_create_kernel_blur_context(void *blur_context, GLfloat *projection,
auto pass = &ctx->blur_shader[1];
pass->prog = gl_create_program_from_strv(
(const char *[]){vertex_shader, NULL},
(const char *[]){copy_with_mask_frag, masking_glsl, NULL});
(const char *[]){blend_with_mask_frag, masking_glsl, NULL});
pass->uniform_pixel_norm = -1;
pass->uniform_opacity = -1;
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
bind_uniform(pass, mask_tex);
bind_uniform(pass, mask_offset);
bind_uniform(pass, mask_inverted);
bind_uniform(pass, mask_corner_radius);
bind_uniform(pass, opacity);
// Setup projection matrix
glUseProgram(pass->prog);

View File

@ -23,12 +23,6 @@
#include "utils.h"
#include "x.h"
struct egl_pixmap {
EGLImage image;
xcb_pixmap_t pixmap;
bool owned;
};
struct egl_data {
struct gl_data gl;
EGLDisplay display;
@ -65,16 +59,11 @@ const char *eglGetErrorString(EGLint error) {
*/
static void egl_release_image(backend_t *base, struct gl_texture *tex) {
struct egl_data *gd = (void *)base;
struct egl_pixmap *p = tex->user_data;
EGLImage *p = tex->user_data;
// Release binding
if (p->image != EGL_NO_IMAGE) {
eglDestroyImage(gd->display, p->image);
p->image = EGL_NO_IMAGE;
}
if (p->owned) {
xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE;
if (p && *p != EGL_NO_IMAGE) {
eglDestroyImage(gd->display, *p);
*p = EGL_NO_IMAGE;
}
free(p);
@ -110,11 +99,7 @@ void egl_deinit(backend_t *base) {
}
static void *egl_decouple_user_data(backend_t *base attr_unused, void *ud attr_unused) {
auto ret = cmalloc(struct egl_pixmap);
ret->owned = false;
ret->image = EGL_NO_IMAGE;
ret->pixmap = 0;
return ret;
return NULL;
}
static bool egl_set_swap_interval(int interval, EGLDisplay dpy) {
@ -250,9 +235,9 @@ end:
}
static image_handle
egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt) {
struct egl_data *gd = (void *)base;
struct egl_pixmap *eglpixmap = NULL;
EGLImage *eglpixmap = NULL;
auto r =
xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), NULL);
@ -273,20 +258,19 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
log_debug("depth %d", fmt.visual_depth);
inner->y_inverted = true;
inner->pixmap = pixmap;
eglpixmap = cmalloc(struct egl_pixmap);
eglpixmap->pixmap = pixmap;
eglpixmap->image = eglCreateImage(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)(uintptr_t)pixmap, NULL);
eglpixmap->owned = owned;
eglpixmap = cmalloc(EGLImage);
*eglpixmap = eglCreateImage(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)(uintptr_t)pixmap, NULL);
if (eglpixmap->image == EGL_NO_IMAGE) {
if (*eglpixmap == EGL_NO_IMAGE) {
log_error("Failed to create eglpixmap for pixmap %#010x: %s", pixmap,
eglGetErrorString(eglGetError()));
goto err;
}
log_trace("EGLImage %p", eglpixmap->image);
log_trace("EGLImage %p", *eglpixmap);
// Create texture
inner->user_data = eglpixmap;
@ -297,20 +281,16 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
wd->dim = 0;
wd->inner->refcount = 1;
glBindTexture(GL_TEXTURE_2D, inner->texture);
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, eglpixmap->image, NULL);
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, *eglpixmap, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
gl_check_err();
return (image_handle)wd;
err:
if (eglpixmap && eglpixmap->image) {
eglDestroyImage(gd->display, eglpixmap->image);
if (eglpixmap && *eglpixmap) {
eglDestroyImage(gd->display, *eglpixmap);
}
free(eglpixmap);
if (owned) {
xcb_free_pixmap(base->c->c, pixmap);
}
free(wd);
return NULL;
}

View File

@ -762,15 +762,19 @@ static void gl_release_image_inner(backend_t *base, struct gl_texture *inner) {
gl_check_err();
}
void gl_release_image(backend_t *base, image_handle image) {
xcb_pixmap_t gl_release_image(backend_t *base, image_handle image) {
auto wd = (struct backend_image *)image;
auto inner = (struct gl_texture *)wd->inner;
inner->refcount--;
assert(inner->refcount >= 0);
xcb_pixmap_t pixmap = XCB_NONE;
if (inner->refcount == 0) {
pixmap = inner->pixmap;
gl_release_image_inner(base, inner);
}
free(wd);
return pixmap;
}
void *gl_create_window_shader(backend_t *backend_data attr_unused, const char *source) {
@ -1176,6 +1180,7 @@ void gl_present(backend_t *base, const region_t *region) {
}
glUseProgram(gd->present_prog);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
GLuint vao;

View File

@ -4,6 +4,7 @@
#include <epoxy/gl.h>
#include <stdbool.h>
#include <string.h>
#include <xcb/xproto.h>
#include "backend/backend.h"
#include "backend/backend_common.h"
@ -83,6 +84,7 @@ struct gl_texture {
GLuint texture;
int width, height;
bool y_inverted;
xcb_pixmap_t pixmap;
// Textures for auxiliary uses.
GLuint auxiliary_texture[2];
@ -165,7 +167,7 @@ GLuint gl_new_texture(GLenum target);
bool gl_image_op(backend_t *base, enum image_operations op, image_handle image,
const region_t *reg_op, const region_t *reg_visible, void *arg);
void gl_release_image(backend_t *base, image_handle image);
xcb_pixmap_t gl_release_image(backend_t *base, image_handle image);
image_handle gl_make_mask(backend_t *base, geometry_t size, const region_t *reg);
image_handle gl_clone(backend_t *base, image_handle image, const region_t *reg_visible);
@ -272,7 +274,7 @@ static const GLuint vert_in_texcoord_loc = 1;
#define GLSL(version, ...) "#version " #version "\n" #__VA_ARGS__
#define QUOTE(...) #__VA_ARGS__
extern const char vertex_shader[], copy_with_mask_frag[], masking_glsl[], dummy_frag[],
extern const char vertex_shader[], blend_with_mask_frag[], masking_glsl[], dummy_frag[],
present_frag[], fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[],
win_shader_glsl[], win_shader_default[], present_vertex_shader[], dither_glsl[],
shadow_colorization_frag[];

View File

@ -36,12 +36,6 @@
#include "win.h"
#include "x.h"
struct _glx_pixmap {
GLXPixmap glpixmap;
xcb_pixmap_t pixmap;
bool owned;
};
struct _glx_data {
struct gl_data gl;
xcb_window_t target_win;
@ -169,23 +163,18 @@ bool glx_find_fbconfig(struct x_connection *c, struct xvisual_info m,
* Free a glx_texture_t.
*/
static void glx_release_image(backend_t *base, struct gl_texture *tex) {
struct _glx_pixmap *p = tex->user_data;
GLXPixmap *p = tex->user_data;
// Release binding
if (p->glpixmap && tex->texture) {
if (p && tex->texture) {
glBindTexture(GL_TEXTURE_2D, tex->texture);
glXReleaseTexImageEXT(base->c->dpy, p->glpixmap, GLX_FRONT_LEFT_EXT);
glXReleaseTexImageEXT(base->c->dpy, *p, GLX_FRONT_LEFT_EXT);
glBindTexture(GL_TEXTURE_2D, 0);
}
// Free GLX Pixmap
if (p->glpixmap) {
glXDestroyPixmap(base->c->dpy, p->glpixmap);
p->glpixmap = 0;
}
if (p->owned) {
xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE;
if (p) {
glXDestroyPixmap(base->c->dpy, *p);
*p = 0;
}
free(p);
@ -217,11 +206,7 @@ void glx_deinit(backend_t *base) {
}
static void *glx_decouple_user_data(backend_t *base attr_unused, void *ud attr_unused) {
auto ret = cmalloc(struct _glx_pixmap);
ret->owned = false;
ret->glpixmap = 0;
ret->pixmap = 0;
return ret;
return NULL;
}
static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawable) {
@ -381,8 +366,8 @@ end:
}
static image_handle
glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
struct _glx_pixmap *glxpixmap = NULL;
glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt) {
GLXPixmap *glxpixmap = NULL;
auto gd = (struct _glx_data *)base;
// Retrieve pixmap parameters, if they aren't provided
if (fmt.visual_depth > OPENGL_MAX_DEPTH) {
@ -453,17 +438,16 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
inner->y_inverted = fbconfig->y_inverted;
glxpixmap = cmalloc(struct _glx_pixmap);
glxpixmap->pixmap = pixmap;
glxpixmap->glpixmap = glXCreatePixmap(base->c->dpy, fbconfig->cfg, pixmap, attrs);
glxpixmap->owned = owned;
glxpixmap = cmalloc(GLXPixmap);
inner->pixmap = pixmap;
*glxpixmap = glXCreatePixmap(base->c->dpy, fbconfig->cfg, pixmap, attrs);
if (!glxpixmap->glpixmap) {
if (!*glxpixmap) {
log_error("Failed to create glpixmap for pixmap %#010x", pixmap);
goto err;
}
log_trace("GLXPixmap %#010lx", glxpixmap->glpixmap);
log_trace("GLXPixmap %#010lx", *glxpixmap);
// Create texture
inner->user_data = glxpixmap;
@ -471,20 +455,16 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
inner->has_alpha = fmt.alpha_size != 0;
wd->inner->refcount = 1;
glBindTexture(GL_TEXTURE_2D, inner->texture);
glXBindTexImageEXT(base->c->dpy, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
glXBindTexImageEXT(base->c->dpy, *glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
gl_check_err();
return (image_handle)wd;
err:
if (glxpixmap && glxpixmap->glpixmap) {
glXDestroyPixmap(base->c->dpy, glxpixmap->glpixmap);
if (glxpixmap && *glxpixmap) {
glXDestroyPixmap(base->c->dpy, *glxpixmap);
}
free(glxpixmap);
if (owned) {
xcb_free_pixmap(base->c->c, pixmap);
}
free(wd);
return NULL;
}

View File

@ -18,12 +18,13 @@ const char present_frag[] = GLSL(330,
}
);
const char copy_with_mask_frag[] = GLSL(330,
const char blend_with_mask_frag[] = GLSL(330,
uniform sampler2D tex;
uniform float opacity;
in vec2 texcoord;
float mask_factor();
void main() {
gl_FragColor = texelFetch(tex, ivec2(texcoord.xy), 0) * mask_factor();
gl_FragColor = texelFetch(tex, ivec2(texcoord.xy), 0) * opacity * mask_factor();
}
);

View File

@ -86,9 +86,9 @@ struct xrender_image_data_inner {
int width, height;
xcb_visualid_t visual;
uint8_t depth;
// Whether we own this image, e.g. we allocated it;
// or not, e.g. this is a named pixmap of a X window.
bool owned;
// Whether we allocated it this pixmap.
// or not, i.e. this pixmap is passed in via xrender_bind_pixmap
bool internal_pixmap;
};
struct xrender_rounded_rectangle_cache {
@ -523,8 +523,8 @@ xrender_blur(backend_t *backend_data, double opacity, void *ctx_, image_handle m
return true;
}
static image_handle xrender_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap,
struct xvisual_info fmt, bool owned) {
static image_handle
xrender_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt) {
xcb_generic_error_t *e;
auto r = xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), &e);
if (!r) {
@ -544,9 +544,9 @@ static image_handle xrender_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap,
xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_NORMAL};
inner->pict = x_create_picture_with_visual_and_pixmap(
base->c, fmt.visual, pixmap, XCB_RENDER_CP_REPEAT, &pic_attrs);
inner->owned = owned;
inner->visual = fmt.visual;
inner->refcount = 1;
inner->internal_pixmap = false;
img->base.inner = (struct backend_image_inner_base *)inner;
img->base.opacity = 1;
@ -560,13 +560,17 @@ static image_handle xrender_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap,
}
return (image_handle)img;
}
static void
static xcb_pixmap_t
xrender_release_image_inner(backend_t *base, struct xrender_image_data_inner *inner) {
x_free_picture(base->c, inner->pict);
if (inner->owned) {
if (inner->internal_pixmap) {
xcb_free_pixmap(base->c->c, inner->pixmap);
inner->pixmap = XCB_NONE;
}
auto ret = inner->pixmap;
free(inner);
return ret;
}
static void
@ -584,16 +588,18 @@ xrender_release_rounded_corner_cache(backend_t *base,
}
}
static void xrender_release_image(backend_t *base, image_handle image) {
static xcb_pixmap_t xrender_release_image(backend_t *base, image_handle image) {
auto img = (struct xrender_image *)image;
xcb_pixmap_t pixmap = XCB_NONE;
xrender_release_rounded_corner_cache(base, img->rounded_rectangle);
img->rounded_rectangle = NULL;
img->base.inner->refcount -= 1;
if (img->base.inner->refcount == 0) {
xrender_release_image_inner(
pixmap = xrender_release_image_inner(
base, (struct xrender_image_data_inner *)img->base.inner);
}
free(img);
return pixmap;
}
static void xrender_deinit(backend_t *backend_data) {
@ -716,7 +722,7 @@ xrender_new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t
new_inner->visual = visual;
new_inner->depth = depth;
new_inner->refcount = 1;
new_inner->owned = true;
new_inner->internal_pixmap = true;
return new_inner;
}

View File

@ -1192,7 +1192,7 @@ void root_damaged(session_t *ps) {
free(r);
ps->root_image = ps->backend_data->ops->bind_pixmap(
ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual), false);
ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual));
if (ps->root_image) {
ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE,

View File

@ -310,25 +310,34 @@ static inline void win_release_pixmap(backend_t *base, struct managed_win *w) {
log_debug("Releasing pixmap of window %#010x (%s)", w->base.id, w->name);
assert(w->win_image);
if (w->win_image) {
base->ops->release_image(base, w->win_image);
auto pixmap = base->ops->release_image(base, w->win_image);
w->win_image = NULL;
// Bypassing win_set_flags, because `w` might have been destroyed
w->flags |= WIN_FLAGS_PIXMAP_NONE;
if (pixmap != XCB_NONE) {
xcb_free_pixmap(base->c->c, pixmap);
}
}
}
static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
log_debug("Releasing shadow of window %#010x (%s)", w->base.id, w->name);
if (w->shadow_image) {
assert(w->shadow);
base->ops->release_image(base, w->shadow_image);
auto pixmap = base->ops->release_image(base, w->shadow_image);
w->shadow_image = NULL;
if (pixmap != XCB_NONE) {
xcb_free_pixmap(base->c->c, pixmap);
}
}
}
static inline void win_release_mask(backend_t *base, struct managed_win *w) {
if (w->mask_image) {
base->ops->release_image(base, w->mask_image);
auto pixmap = base->ops->release_image(base, w->mask_image);
w->mask_image = NULL;
if (pixmap != XCB_NONE) {
xcb_free_pixmap(base->c->c, pixmap);
}
}
}
@ -344,10 +353,10 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
return false;
}
log_debug("New named pixmap for %#010x (%s) : %#010x", w->base.id, w->name, pixmap);
w->win_image =
b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual), true);
w->win_image = b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual));
if (!w->win_image) {
log_error("Failed to bind pixmap");
xcb_free_pixmap(b->c->c, pixmap);
win_set_flags(w, WIN_FLAGS_IMAGE_ERROR);
return false;
}
@ -1568,6 +1577,7 @@ void free_win_res(session_t *ps, struct managed_win *w) {
// Above should be done during unmapping
// Except when we are called by session_destroy
pixman_region32_fini(&w->damaged);
pixman_region32_fini(&w->bounding_shape);
// BadDamage may be thrown if the window is destroyed
set_ignore_cookie(&ps->c, xcb_damage_destroy(ps->c.c, w->damage));
@ -2180,7 +2190,6 @@ void destroy_win_finish(session_t *ps, struct win *w) {
w2->prev_trans = NULL;
}
}
pixman_region32_fini(&mw->damaged);
}
free(w);