1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2025-04-14 17:53:25 -04:00

general: remove code related to the legacy backends

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-10-13 17:22:11 +01:00
parent 2f917fda23
commit a54adb62da
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
26 changed files with 258 additions and 4524 deletions

View file

@ -53,7 +53,7 @@ libconfig-dev libdbus-1-dev libegl-dev libev-dev libgl-dev libepoxy-dev libpcre2
On Fedora, the needed packages are
```
dbus-devel gcc git libconfig-devel libdrm-devel libev-devel libX11-devel libX11-xcb libxcb-devel libGL-devel libEGL-devel libepoxy-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel xcb-util-devel
dbus-devel gcc git libconfig-devel libev-devel libX11-devel libX11-xcb libxcb-devel libGL-devel libEGL-devel libepoxy-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel xcb-util-devel
```
To build the documents, you need `asciidoctor`

View file

@ -1,8 +1,6 @@
option('sanitize', type: 'boolean', value: false, description: 'Build with sanitizers enabled (deprecated)')
option('regex', type: 'boolean', value: true, description: 'Enable regex support in window conditions')
option('vsync_drm', type: 'boolean', value: false, description: 'Enable support for using drm for vsync')
option('opengl', type: 'boolean', value: true, description: 'Enable features that require opengl (opengl backend, and opengl vsync methods)')
option('dbus', type: 'boolean', value: true, description: 'Enable support for D-Bus remote control')

View file

@ -34,10 +34,6 @@
#include <picom/backend.h>
#include <picom/types.h>
#ifdef CONFIG_OPENGL
#include "backend/gl/glx.h"
#endif
// X resource checker
#ifdef DEBUG_XRC
#include "xrescheck.h"
@ -47,7 +43,6 @@
#include "backend/driver.h"
#include "config.h"
#include "region.h"
#include "render.h"
#include "utils/statistics.h"
#include "wm/defs.h"
#include "x.h"
@ -64,47 +59,9 @@
// Window flags
// === Types ===
typedef struct glx_fbconfig glx_fbconfig_t;
struct glx_session;
struct atom;
struct conv;
#ifdef CONFIG_OPENGL
#ifdef DEBUG_GLX_DEBUG_CONTEXT
typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config,
GLXContext share_context, Bool direct,
const int *attrib_list);
typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar *message, GLvoid *userParam);
typedef void (*f_DebugMessageCallback)(GLDEBUGPROC, void *userParam);
#endif
typedef struct glx_prog_main {
/// GLSL program.
GLuint prog;
/// Location of uniform "opacity" in window GLSL program.
GLint unifm_opacity;
/// Location of uniform "invert_color" in blur GLSL program.
GLint unifm_invert_color;
/// Location of uniform "tex" in window GLSL program.
GLint unifm_tex;
/// Location of uniform "time" in window GLSL program.
GLint unifm_time;
} glx_prog_main_t;
#define GLX_PROG_MAIN_INIT \
{ \
.prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, \
.unifm_tex = -1, .unifm_time = -1 \
}
#else
struct glx_prog_main {};
#endif
#define PAINT_INIT \
{ .pixmap = XCB_NONE, .pict = XCB_NONE }
/// Linked list type of atoms.
typedef struct _latom {
xcb_atom_t atom;
@ -119,18 +76,6 @@ struct shader_info {
UT_hash_handle hh;
};
struct damage_ring {
/// Cache a xfixes region so we don't need to allocate it every time.
/// A workaround for yshui/picom#301
xcb_xfixes_region_t x_region;
/// The region needs to painted on next paint.
int cursor;
/// The region damaged on the last paint.
region_t *damages;
/// Number of damage regions we track
int count;
};
/// Structure containing all necessary data for a session.
typedef struct session {
// === Event handlers ===
@ -174,10 +119,6 @@ typedef struct session {
xcb_window_t overlay;
/// The target window for debug mode
xcb_window_t debug_window;
/// Whether the root tile is filled by us.
bool root_tile_fill;
/// Picture of the root window background.
paint_t root_tile_paint;
/// The backend data the root pixmap bound to
image_handle root_image;
/// The root pixmap generation, incremented everytime
@ -185,23 +126,8 @@ typedef struct session {
uint64_t root_image_generation;
/// A region of the size of the screen.
region_t screen_reg;
/// Picture of root window. Destination of painting in no-DBE painting
/// mode.
xcb_render_picture_t root_picture;
/// A Picture acting as the painting target.
xcb_render_picture_t tgt_picture;
/// Temporary buffer to paint to before sending to display.
paint_t tgt_buffer;
/// Window ID of the window we register as a symbol.
xcb_window_t reg_win;
#ifdef CONFIG_OPENGL
/// Pointer to GLX data.
struct glx_session *psglx;
/// Custom GLX program used for painting window.
// XXX should be in struct glx_session
glx_prog_main_t glx_prog_win;
struct glx_fbconfig_info argb_fbconfig;
#endif
/// Sync fence to sync draw operations
xcb_sync_fence_t sync_fence;
/// Whether we are rendering the first frame after screen is redirected
@ -246,9 +172,8 @@ typedef struct session {
/// to the screen that's neither included in the current render, nor on the
/// screen.
bool render_queued;
// TODO(yshui) remove this after we remove the legacy backends
/// For tracking damage regions
struct damage_ring damage_ring;
/// A X region used for various operations. Kept to avoid repeated allocation.
xcb_xfixes_region_t x_region;
// TODO(yshui) move render related fields into separate struct
/// Render planner
struct layout_manager *layout_manager;
@ -261,8 +186,6 @@ typedef struct session {
xcb_render_picture_t *alpha_picts;
/// Time of last fading. In milliseconds.
long long fade_time;
// Cached blur convolution kernels.
struct x_convolution_kernel **blur_kerns_cache;
/// If we should quit
bool quit : 1;
// TODO(yshui) use separate flags for different kinds of updates so we don't
@ -270,12 +193,6 @@ typedef struct session {
/// Whether there are pending updates, like window creation, etc.
bool pending_updates : 1;
// === Expose event related ===
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
/// This is a reuse temporary buffer for handling root expose events.
/// This is a dynarr.
rect_t *expose_rects;
struct wm *wm;
struct window_options window_options_default;
@ -295,12 +212,6 @@ typedef struct session {
/// Nanosecond offset of the first painting.
long paint_tm_offset;
#ifdef CONFIG_VSYNC_DRM
// === DRM VSync related ===
/// File descriptor of DRI device file. Used for DRM VSync.
int drm_fd;
#endif
// === X extension related ===
/// Event base number for X Fixes extension.
int xfixes_event;
@ -348,8 +259,6 @@ typedef struct session {
int xsync_event;
/// Error base number for X Sync extension.
int xsync_error;
/// Whether X Render convolution filter exists.
bool xrfilter_convolution_exists;
// === Atoms ===
struct atom *atoms;
@ -358,8 +267,6 @@ typedef struct session {
// === DBus related ===
struct cdbus_data *dbus_data;
#endif
int (*vsync_wait)(session_t *);
} session_t;
/// Enumeration for window event hints.
@ -441,13 +348,6 @@ static inline xcb_window_t get_tgt_window(session_t *ps) {
return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
}
/**
* Check if current backend uses GLX.
*/
static inline bool bkend_use_glx(session_t *ps) {
return BKEND_GLX == ps->o.legacy_backend || BKEND_XR_GLX_HYBRID == ps->o.legacy_backend;
}
/**
* Determine if a window has a specific property.
*
@ -484,24 +384,3 @@ static inline void wintype_arr_enable(bool arr[]) {
arr[i] = true;
}
}
static inline void damage_ring_advance(struct damage_ring *ring) {
ring->cursor--;
if (ring->cursor < 0) {
ring->cursor += ring->count;
}
pixman_region32_clear(&ring->damages[ring->cursor]);
}
static inline void damage_ring_collect(struct damage_ring *ring, region_t *all_region,
region_t *region, int buffer_age) {
if (buffer_age == -1 || buffer_age > ring->count) {
pixman_region32_copy(region, all_region);
} else {
for (int i = 0; i < buffer_age; i++) {
auto curr = (ring->cursor + i) % ring->count;
pixman_region32_union(region, region, &ring->damages[curr]);
}
pixman_region32_intersect(region, region, all_region);
}
}

View file

@ -642,8 +642,6 @@ bool load_plugin(const char *name, const char *include_dir) {
bool parse_config(options_t *opt, const char *config_file) {
// clang-format off
*opt = (struct options){
.legacy_backend = BKEND_XRENDER,
.use_legacy_backends = false,
.glx_no_stencil = false,
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,

View file

@ -251,8 +251,6 @@ typedef struct options {
char *write_pid_path;
/// Name of the backend
struct backend_info *backend;
/// The backend in use (for legacy backends).
int legacy_backend;
/// Log level.
int log_level;
/// Whether to sync X drawing with X Sync fence to avoid certain delay

View file

@ -929,9 +929,8 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) {
lcfg_lookup_bool(&cfg, "vsync", &opt->vsync);
// --backend
if (config_lookup_string(&cfg, "backend", &sval)) {
opt->legacy_backend = parse_backend(sval);
opt->backend = backend_find(sval);
if (opt->legacy_backend >= NUM_BKEND && opt->backend == NULL) {
if (opt->backend == NULL) {
log_fatal("Invalid backend: %s", sval);
goto out;
}

View file

@ -826,7 +826,6 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
return DBUS_HANDLER_RESULT_HANDLED;
}
if (changed) {
add_damage_from_win(ps, w);
queue_redraw(ps);
}
@ -908,11 +907,7 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
#define append_session_option(tgt, type) append(tgt, type, ps->o.tgt)
if (strcmp("backend", target) == 0) {
assert(!ps->o.use_legacy_backends ||
(size_t)ps->o.legacy_backend < ARR_SIZE(BACKEND_STRS));
const char *name = ps->o.use_legacy_backends
? BACKEND_STRS[ps->o.legacy_backend]
: backend_name(ps->o.backend);
const char *name = backend_name(ps->o.backend);
if (reply != NULL && !cdbus_append_string(reply, name)) {
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
@ -930,7 +925,6 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
append(unredir_if_possible_delay, int32, (int32_t)ps->o.unredir_if_possible_delay);
append(refresh_rate, int32, 0);
append(sw_opti, boolean, false);
append(backend, string, BACKEND_STRS[ps->o.legacy_backend]);
append_session_option(unredir_if_possible, boolean);
append_session_option(write_pid_path, string);

View file

@ -375,7 +375,6 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
w->a.override_redirect = ce->override_redirect;
if (w->state == WSTATE_MAPPED) {
add_damage_from_win(ps, w);
ps->pending_updates |= changed;
}
}
@ -515,37 +514,16 @@ static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event
log_debug("Moving window %#010x (%s) to the %s", ev->window,
ev_window_name(ps, ev->window), ev->place == PlaceOnTop ? "top" : "bottom");
wm_stack_move_to_end(ps->wm, cursor, ev->place == XCB_PLACE_ON_BOTTOM);
auto w = wm_ref_deref(cursor);
if (w != NULL) {
add_damage_from_win(ps, w);
}
}
static inline void expose_root(session_t *ps, const rect_t *rects, size_t nrects) {
region_t region;
pixman_region32_init_rects(&region, rects, (int)nrects);
add_damage(ps, &region);
pixman_region32_fini(&region);
}
static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) {
if (ev->window == ps->c.screen_info->root ||
(ps->overlay && ev->window == ps->overlay)) {
dynarr_reserve(ps->expose_rects, ev->count + 1);
if (ev->window != ps->c.screen_info->root &&
(ps->overlay == XCB_NONE || ev->window != ps->overlay)) {
return;
}
rect_t new_rect = {
.x1 = ev->x,
.y1 = ev->y,
.x2 = ev->x + ev->width,
.y2 = ev->y + ev->height,
};
dynarr_push(ps->expose_rects, new_rect);
if (ev->count == 0) {
expose_root(ps, ps->expose_rects, dynarr_len(ps->expose_rects));
dynarr_clear_pod(ps->expose_rects);
}
if (ev->count == 0) {
force_repaint(ps);
}
}
@ -673,12 +651,11 @@ static inline void repair_win(session_t *ps, struct win *w) {
log_debug("Window %#010x (%s) has been damaged the first time", win_id(w),
w->name);
} else {
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
ps->damage_ring.x_region);
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE, ps->x_region);
if (!ps->o.show_all_xerrors) {
x_set_error_action_ignore(&ps->c, cookie);
}
x_fetch_region(&ps->c, ps->damage_ring.x_region, &parts);
x_fetch_region(&ps->c, ps->x_region, &parts);
pixman_region32_translate(&parts, w->g.x + w->g.border_width,
w->g.y + w->g.border_width);
}
@ -694,16 +671,6 @@ static inline void repair_win(session_t *ps, struct win *w) {
return;
}
// Remove the part in the damage area that could be ignored
region_t without_ignored;
pixman_region32_init(&without_ignored);
if (w->reg_ignore && win_is_region_ignore_valid(ps, w)) {
pixman_region32_subtract(&without_ignored, &parts, w->reg_ignore);
}
add_damage(ps, &without_ignored);
pixman_region32_fini(&without_ignored);
pixman_region32_translate(&parts, -w->g.x, -w->g.y);
pixman_region32_union(&w->damaged, &w->damaged, &parts);
pixman_region32_fini(&parts);
@ -736,20 +703,6 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev)
return;
}
/*
* Empty bounding_shape may indicated an
* unmapped/destroyed window, in which case
* seemingly BadRegion errors would be triggered
* if we attempt to rebuild border_size
*/
// Mark the old bounding shape as damaged
if (!win_check_flags_any(w, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
region_t tmp = win_get_bounding_shape_global_by_val(w);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);
}
w->reg_ignore_valid = false;
win_set_flags(w, WIN_FLAGS_SIZE_STALE);
ps->pending_updates = true;
}

View file

@ -17,9 +17,7 @@ srcs = [
'log.c',
'options.c',
'picom.c',
'render.c',
'vblank.c',
'vsync.c',
'x.c',
),
]
@ -90,15 +88,9 @@ if get_option('regex')
deps += [pcre]
endif
if get_option('vsync_drm')
cflags += ['-DCONFIG_VSYNC_DRM']
deps += [dependency('libdrm', required: true)]
endif
if get_option('opengl')
cflags += ['-DCONFIG_OPENGL']
deps += [dependency('epoxy', required: true)]
srcs += ['opengl.c']
endif
if get_option('dbus')

File diff suppressed because it is too large Load diff

View file

@ -1,227 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2011-2013, Christopher Jeffrey
#pragma once
#include "common.h"
#include "compiler.h"
#include "region.h"
#include "render.h"
#include "wm/win.h"
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
typedef struct {
/// Fragment shader for blur.
GLuint frag_shader;
/// GLSL program for blur.
GLuint prog;
/// Location of uniform "offset_x" in blur GLSL program.
GLint unifm_offset_x;
/// Location of uniform "offset_y" in blur GLSL program.
GLint unifm_offset_y;
/// Location of uniform "factor_center" in blur GLSL program.
GLint unifm_factor_center;
} glx_blur_pass_t;
typedef struct {
/// Fragment shader for rounded corners.
GLuint frag_shader;
/// GLSL program for rounded corners.
GLuint prog;
/// Location of uniform "radius" in rounded-corners GLSL program.
GLint unifm_radius;
/// Location of uniform "texcoord" in rounded-corners GLSL program.
GLint unifm_texcoord;
/// Location of uniform "texsize" in rounded-corners GLSL program.
GLint unifm_texsize;
/// Location of uniform "borderw" in rounded-corners GLSL program.
GLint unifm_borderw;
/// Location of uniform "borderc" in rounded-corners GLSL program.
GLint unifm_borderc;
/// Location of uniform "resolution" in rounded-corners GLSL program.
GLint unifm_resolution;
/// Location of uniform "texture_scr" in rounded-corners GLSL program.
GLint unifm_tex_scr;
} glx_round_pass_t;
/// Structure containing GLX-dependent data for a session.
typedef struct glx_session {
// === OpenGL related ===
/// GLX context.
GLXContext context;
/// Whether we have GL_ARB_texture_non_power_of_two.
bool has_texture_non_power_of_two;
/// Current GLX Z value.
int z;
glx_blur_pass_t *blur_passes;
glx_round_pass_t *round_passes;
} glx_session_t;
/// @brief Wrapper of a bound GLX texture.
typedef struct _glx_texture {
GLuint texture;
GLXPixmap glpixmap;
xcb_pixmap_t pixmap;
GLenum target;
int width;
int height;
bool y_inverted;
} glx_texture_t;
#define CGLX_SESSION_INIT \
{ .context = NULL }
bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
GLfloat factor, const region_t *reg_tgt);
bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy,
int width, int height, int z, double opacity, bool argb, bool neg,
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
bool glx_init(session_t *ps, bool need_render);
void glx_destroy(session_t *ps);
void glx_on_root_change(session_t *ps);
bool glx_init_blur(session_t *ps);
bool glx_init_rounded_corners(session_t *ps);
#ifdef CONFIG_OPENGL
bool glx_load_prog_main(const char *vshader_str, const char *fshader_str,
glx_prog_main_t *pprogram);
#endif
bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, int width,
int height, bool repeat, const struct glx_fbconfig_info *);
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int width, int height);
void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);
/**
* Check if a texture is bound, or is bound to the given pixmap.
*/
static inline bool glx_tex_bound(const glx_texture_t *ptex, xcb_pixmap_t pixmap) {
return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap);
}
void glx_set_clip(session_t *ps, const region_t *reg);
bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);
bool glx_round_corners_dst(session_t *ps, struct win *w, const glx_texture_t *ptex,
int dx, int dy, int width, int height, float z, float cr,
const region_t *reg_tgt);
GLuint glx_create_shader(GLenum shader_type, const char *shader_str);
GLuint glx_create_program(const GLuint *const shaders, int nshaders);
GLuint glx_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
unsigned char *glx_take_screenshot(session_t *ps, int *out_length);
/**
* Check if there's a GLX context.
*/
static inline bool glx_has_context(session_t *ps) {
return ps->psglx && ps->psglx->context;
}
/**
* Ensure we have a GLX context.
*/
static inline bool ensure_glx_context(session_t *ps) {
// Create GLX context
if (!glx_has_context(ps)) {
glx_init(ps, false);
}
return glx_has_context(ps);
}
/**
* Free a GLX texture.
*/
static inline void free_texture_r(session_t *ps attr_unused, GLuint *ptexture) {
if (*ptexture) {
assert(glx_has_context(ps));
glDeleteTextures(1, ptexture);
*ptexture = 0;
}
}
/**
* Free a GLX Framebuffer object.
*/
static inline void free_glx_fbo(GLuint *pfbo) {
if (*pfbo) {
glDeleteFramebuffers(1, pfbo);
*pfbo = 0;
}
assert(!*pfbo);
}
/**
* Free data in glx_blur_cache_t on resize.
*/
static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
free_texture_r(ps, &pbc->textures[0]);
free_texture_r(ps, &pbc->textures[1]);
pbc->width = 0;
pbc->height = 0;
}
/**
* Free a glx_blur_cache_t
*/
static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
free_glx_fbo(&pbc->fbo);
free_glx_bc_resize(ps, pbc);
}
/**
* Free a glx_texture_t.
*/
static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
glx_texture_t *ptex = *pptex;
// Quit if there's nothing
if (!ptex) {
return;
}
glx_release_pixmap(ps, ptex);
free_texture_r(ps, &ptex->texture);
// Free structure itself
free(ptex);
*pptex = NULL;
}
/**
* Free GLX part of paint_t.
*/
static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
free_texture(ps, &ppaint->ptex);
ppaint->fbcfg = (struct glx_fbconfig_info){0};
}
/**
* Free GLX part of win.
*/
void free_win_res_glx(session_t *ps, struct win *w);

View file

@ -144,6 +144,15 @@ static bool store_string(const struct picom_option * /*opt*/, const struct picom
return true;
}
static bool
store_fixed_string(const struct picom_option * /*opt*/, const struct picom_arg *arg,
const char * /*arg_str*/, void *output) {
char **dst = (char **)(output + arg->offset);
free(*dst);
*dst = strdup((const char *)arg->user_data);
return true;
}
static bool store_rules(const struct picom_option *arg_opt, const struct picom_arg *arg,
const char *arg_str, void *output) {
const struct picom_rules_parser *parser = arg->user_data;
@ -275,6 +284,11 @@ static bool say_deprecated(const struct picom_option *opt, const struct picom_ar
.offset = OFFSET(member), .handler = store_fixed_enum, \
.user_data = (int[]){value}, \
}
#define FIXED_STR(member, str) \
no_argument, { \
.offset = OFFSET(member), .handler = store_fixed_string, \
.user_data = (void *)(str) \
}
#define SAY_DEPRECATED_(error_, msg, has_arg, ...) \
has_arg, { \
@ -347,9 +361,8 @@ store_benchmark_wid(const struct picom_option * /*opt*/, const struct picom_arg
static bool store_backend(const struct picom_option * /*opt*/, const struct picom_arg * /*arg*/,
const char *arg_str, void *output) {
struct options *opt = (struct options *)output;
opt->legacy_backend = parse_backend(arg_str);
opt->backend = backend_find(arg_str);
if (opt->legacy_backend == NUM_BKEND && opt->backend == NULL) {
if (opt->backend == NULL) {
log_error("Invalid backend: %s", arg_str);
return false;
}
@ -444,7 +457,7 @@ static const struct picom_option picom_options[] = {
"rendered screen. Reduces banding artifacts, but might cause performance "
"degradation. Only works with OpenGL."},
[341] = {"no-frame-pacing" , DISABLE(frame_pacing) , "Disable frame pacing. This might increase the latency."},
[733] = {"legacy-backends" , ENABLE(use_legacy_backends) , "Use deprecated version of the backends."},
[733] = {"legacy-backends" , WARN_DEPRECATED(ENABLE(use_legacy_backends)), NULL},
[800] = {"monitor-repaint" , ENABLE(monitor_repaint) , "Highlight the updated area of the screen. For debugging."},
[801] = {"diagnostics" , ENABLE(print_diagnostics) , "Print diagnostic information"},
[802] = {"debug-mode" , ENABLE(debug_mode) , "Render into a separate window, and don't take over the screen. Useful when "
@ -483,8 +496,8 @@ static const struct picom_option picom_options[] = {
[331] = {"blur-strength" , INTEGER(blur_strength, 0, INT_MAX) , "The strength level of the 'dual_kawase' blur method."},
[333] = {"corner-radius" , INTEGER(corner_radius, 0, INT_MAX) , "Sets the radius of rounded window corners. When > 0, the compositor will "
"round the corners of windows. (defaults to 0)."},
[336] = {"window-shader-fg" , NAMED_STRING(window_shader_fg, "PATH") , "Specify GLSL fragment shader path for rendering window contents. Does not"
" work when `--legacy-backends` is enabled. See man page for more details."},
[336] = {"window-shader-fg" , NAMED_STRING(window_shader_fg, "PATH") , "Specify GLSL fragment shader path for rendering window contents. See man "
"page for more details."},
[294] = {"benchmark-wid" , DO(store_benchmark_wid) , "Specify window ID to repaint in benchmark mode. If omitted or is 0, the whole"
" screen is repainted."},
[301] = {"blur-kern" , DO(store_blur_kern) , "Specify the blur convolution kernel, see man page for more details"},
@ -513,8 +526,7 @@ static const struct picom_option picom_options[] = {
[337] = {"window-shader-fg-rule" , NAMED_RULES(window_shader_fg_rules, "PATH", WINDOW_SHADER_RULE),
"Specify GLSL fragment shader path for rendering window contents using patterns. Pattern should be "
"in the format of SHADER_PATH:PATTERN, similar to --opacity-rule. SHADER_PATH can be \"default\", "
"in which case the default shader will be used. Does not work when --legacy-backends is enabled. See "
"man page for more details"},
"in which case the default shader will be used. See man page for more details"},
[340] = {"corner-radius-rules" , NUMERIC_RULES(corner_radius_rules, "RADIUS", 0, INT_MAX),
"Window rules for specific rounded corner radii."},
@ -523,8 +535,7 @@ static const struct picom_option picom_options[] = {
"Log level, possible values are: trace, debug, info, warn, error"},
[328] = {"blur-method", PARSE_WITH(parse_blur_method, BLUR_METHOD_INVALID, blur_method),
"The algorithm used for background bluring. Available choices are: 'none' to disable, 'gaussian', "
"'box' or 'kernel' for custom convolution blur with --blur-kern. Note: 'gaussian' and 'box' is not "
"supported by --legacy-backends."},
"'box' or 'kernel' for custom convolution blur with --blur-kern."},
// Deprecated options
[274] = {"sw-opti" , ERROR_DEPRECATED(no_argument)},
@ -546,7 +557,7 @@ static const struct picom_option picom_options[] = {
['z'] = {"clear-shadow" , SAY_DEPRECATED(false, CLEAR_SHADOW_DEPRECATION , IGNORE(no_argument))},
[272] = {"xinerama-shadow-crop", SAY_DEPRECATED(false, "Use --crop-shadow-to-monitor instead.", ENABLE(crop_shadow_to_monitor))},
[287] = {"logpath" , SAY_DEPRECATED(false, "Use --log-file instead." , STRING(logpath))},
[289] = {"opengl" , SAY_DEPRECATED(false, "Use --backend=glx instead." , FIXED(legacy_backend, BKEND_GLX))},
[289] = {"opengl" , SAY_DEPRECATED(false, "Use --backend=glx instead." , FIXED_STR(backend, "glx"))},
[305] = {"shadow-exclude-reg" , SAY_DEPRECATED(true, "Use --clip-shadow-above instead." , REJECT(required_argument))},
#undef CLEAR_SHADOW_DEPRECATION
@ -811,108 +822,24 @@ static void script_ptr_deinit(struct script **ptr) {
}
static bool sanitize_options(struct options *opt) {
if (opt->use_legacy_backends) {
if (opt->legacy_backend == BKEND_EGL) {
log_error("The egl backend is not supported with "
"--legacy-backends");
return false;
if (opt->backend == NULL) {
log_error("Backend not specified. You must choose one "
"explicitly. Valid ones are: ");
for (auto i = backend_iter(); i; i = backend_iter_next(i)) {
log_error("\t%s", backend_name(i));
}
return false;
}
if (opt->monitor_repaint && opt->legacy_backend != BKEND_XRENDER) {
log_warn("For legacy backends, --monitor-repaint is only "
"implemented for "
"xrender.");
}
if (opt->glx_fshader_win_str) {
log_warn("--glx-fshader-win has been replaced by "
"\"--window-shader-fg\" for the new backends.");
}
if (opt->debug_mode) {
log_error("Debug mode does not work with the legacy backends.");
return false;
}
if (opt->transparent_clipping) {
log_error("Transparent clipping does not work with the legacy "
"backends");
return false;
}
if (opt->max_brightness < 1.0) {
log_warn("--max-brightness is not supported by the legacy "
"backends. Falling back to 1.0.");
opt->max_brightness = 1.0;
}
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE) {
log_warn("Dual-kawase blur is not implemented by the legacy "
"backends.");
opt->blur_method = BLUR_METHOD_NONE;
}
if (dynarr_len(opt->all_scripts) > 0) {
log_warn("Custom animations are not supported by the legacy "
"backends. Disabling animations.");
for (size_t i = 0; i < ARR_SIZE(opt->animations); i++) {
opt->animations[i].script = NULL;
}
dynarr_clear(opt->all_scripts, script_ptr_deinit);
}
if (opt->window_shader_fg || !list_is_empty(&opt->window_shader_fg_rules)) {
log_warn("The new shader interface is not supported by the "
"legacy glx backend. You may want to use "
"--glx-fshader-win instead.");
opt->window_shader_fg = NULL;
c2_list_free(&opt->window_shader_fg_rules, free);
}
if (opt->legacy_backend == BKEND_XRENDER) {
bool has_neg = false;
for (int i = 0; i < opt->blur_kernel_count; i++) {
auto kernel = opt->blur_kerns[i];
for (int j = 0; j < kernel->h * kernel->w; j++) {
if (kernel->data[j] < 0) {
has_neg = true;
break;
}
}
if (has_neg) {
log_warn("A convolution kernel with negative "
"values may not work properly under X "
"Render backend.");
break;
}
}
}
} else {
if (opt->backend == NULL) {
auto valid_backend_name =
backend_find(BACKEND_STRS[opt->legacy_backend]) != NULL;
if (!valid_backend_name) {
log_error("Backend \"%s\" is only available as part of "
"the legacy backends.",
BACKEND_STRS[opt->legacy_backend]);
} else {
// If the backend name is a valid new backend, then
// it must not have been specified by the user, because
// otherwise opt->backend wouldn't be NULL.
log_error("Backend not specified. You must choose one "
"explicitly. Valid ones are: ");
for (auto i = backend_iter(); i; i = backend_iter_next(i)) {
log_error("\t%s", backend_name(i));
}
}
return false;
}
if (opt->glx_fshader_win_str) {
log_warn("--glx-fshader-win has been replaced by "
"\"--window-shader-fg\" for the new backends.");
}
if (opt->max_brightness < 1.0 && opt->use_damage) {
log_warn("--max-brightness requires --no-use-damage. "
"Falling back to 1.0.");
opt->max_brightness = 1.0;
}
if (opt->max_brightness < 1.0 && opt->use_damage) {
log_warn("--max-brightness requires --no-use-damage. "
"Falling back to 1.0.");
opt->max_brightness = 1.0;
}
if (opt->write_pid_path && *opt->write_pid_path != '/') {

View file

@ -39,10 +39,6 @@
#include <picom/types.h>
#include <test.h>
#ifdef CONFIG_OPENGL
#include "opengl.h"
#endif
#include "api_internal.h"
#include "atom.h"
#include "backend/backend.h"
@ -58,7 +54,6 @@
#include "options.h"
#include "picom.h"
#include "region.h"
#include "render.h"
#include "renderer/command_builder.h"
#include "renderer/layout.h"
#include "renderer/renderer.h"
@ -426,22 +421,6 @@ static inline void get_screen_region(session_t *ps, region_t *res) {
pixman_region32_init_rects(res, &b, 1);
}
void add_damage(session_t *ps, const region_t *damage) {
// Ignore damage when screen isn't redirected
if (!ps->redirected) {
return;
}
if (!damage || ps->damage_ring.count <= 0) {
return;
}
log_trace("Adding damage: ");
dump_region(damage);
auto cursor = &ps->damage_ring.damages[ps->damage_ring.cursor];
pixman_region32_union(cursor, cursor, (region_t *)damage);
}
// === Windows ===
/**
@ -480,7 +459,6 @@ static void destroy_backend(session_t *ps) {
win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE);
win_release_images(ps->backend_data, w);
}
free_paint(ps, &w->paint);
if (w->state == WSTATE_DESTROYED) {
win_destroy_finish(ps, w);
@ -556,76 +534,71 @@ static bool initialize_blur(session_t *ps) {
/// Init the backend and bind all the window pixmap to backend images
static bool initialize_backend(session_t *ps) {
if (!ps->o.use_legacy_backends) {
assert(!ps->backend_data);
// Reinitialize win_data
ps->backend_data =
backend_init(ps->o.backend, ps, session_get_target_window(ps));
api_backend_plugins_invoke(backend_name(ps->o.backend), ps->backend_data);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
quit(ps);
return false;
}
assert(!ps->backend_data);
// Reinitialize win_data
ps->backend_data = backend_init(ps->o.backend, ps, session_get_target_window(ps));
api_backend_plugins_invoke(backend_name(ps->o.backend), ps->backend_data);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
quit(ps);
return false;
}
if (!initialize_blur(ps)) {
log_fatal("Failed to prepare for background blur, aborting...");
goto err;
}
if (!initialize_blur(ps)) {
log_fatal("Failed to prepare for background blur, aborting...");
goto err;
}
// Create shaders
if (!ps->backend_data->ops.create_shader && ps->shaders) {
log_warn("Shaders are not supported by selected backend %s, "
"they will be ignored",
backend_name(ps->o.backend));
} else {
HASH_ITER2(ps->shaders, shader) {
assert(shader->backend_shader == NULL);
shader->backend_shader = ps->backend_data->ops.create_shader(
ps->backend_data, shader->source);
if (shader->backend_shader == NULL) {
log_warn("Failed to create shader for shader "
"file %s, this shader will not be used",
shader->key);
} else {
shader->attributes = 0;
if (ps->backend_data->ops.get_shader_attributes) {
shader->attributes =
ps->backend_data->ops.get_shader_attributes(
ps->backend_data,
shader->backend_shader);
}
log_debug("Shader %s has attributes %" PRIu64,
shader->key, shader->attributes);
// Create shaders
if (!ps->backend_data->ops.create_shader && ps->shaders) {
log_warn("Shaders are not supported by selected backend %s, "
"they will be ignored",
backend_name(ps->o.backend));
} else {
HASH_ITER2(ps->shaders, shader) {
assert(shader->backend_shader == NULL);
shader->backend_shader = ps->backend_data->ops.create_shader(
ps->backend_data, shader->source);
if (shader->backend_shader == NULL) {
log_warn("Failed to create shader for shader "
"file %s, this shader will not be used",
shader->key);
} else {
shader->attributes = 0;
if (ps->backend_data->ops.get_shader_attributes) {
shader->attributes =
ps->backend_data->ops.get_shader_attributes(
ps->backend_data, shader->backend_shader);
}
log_debug("Shader %s has attributes %" PRIu64,
shader->key, shader->attributes);
}
}
wm_stack_foreach(ps->wm, cursor) {
auto w = wm_ref_deref(cursor);
if (w != NULL) {
assert(w->state != WSTATE_DESTROYED);
// We need to reacquire image
log_debug("Marking window %#010x (%s) for update after "
"redirection",
win_id(w), w->name);
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
ps->pending_updates = true;
}
}
ps->renderer = renderer_new(ps->backend_data, ps->o.shadow_radius,
(struct color){.alpha = ps->o.shadow_opacity,
.red = ps->o.shadow_red,
.green = ps->o.shadow_green,
.blue = ps->o.shadow_blue},
ps->o.dithered_present);
if (!ps->renderer) {
log_fatal("Failed to create renderer, aborting...");
goto err;
}
}
// The old backends binds pixmap lazily, nothing to do here
wm_stack_foreach(ps->wm, cursor) {
auto w = wm_ref_deref(cursor);
if (w != NULL) {
assert(w->state != WSTATE_DESTROYED);
// We need to reacquire image
log_debug("Marking window %#010x (%s) for update after "
"redirection",
win_id(w), w->name);
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
ps->pending_updates = true;
}
}
ps->renderer = renderer_new(ps->backend_data, ps->o.shadow_radius,
(struct color){.alpha = ps->o.shadow_opacity,
.red = ps->o.shadow_red,
.green = ps->o.shadow_green,
.blue = ps->o.shadow_blue},
ps->o.dithered_present);
if (!ps->renderer) {
log_fatal("Failed to create renderer, aborting...");
goto err;
}
return true;
err:
ps->backend_data->ops.deinit(ps->backend_data);
@ -634,18 +607,6 @@ err:
return false;
}
static inline void invalidate_reg_ignore(session_t *ps) {
// Invalidate reg_ignore from the top
wm_stack_foreach(ps->wm, cursor) {
auto top_w = wm_ref_deref(cursor);
if (top_w != NULL) {
rc_region_unref(&top_w->reg_ignore);
top_w->reg_ignore_valid = false;
break;
}
}
}
/// Handle configure event of the root window
void configure_root(session_t *ps) {
// TODO(yshui) re-initializing backend should be done outside of the
@ -657,23 +618,14 @@ void configure_root(session_t *ps) {
}
log_info("Root configuration changed, new geometry: %dx%d", r->width, r->height);
bool has_root_change = false;
if (ps->redirected) {
// On root window changes
if (!ps->o.use_legacy_backends) {
assert(ps->backend_data);
has_root_change = ps->backend_data->ops.root_change != NULL;
} else {
// Old backend can handle root change
has_root_change = true;
}
if (!has_root_change) {
BUG_ON_NULL(ps->backend_data);
if (ps->backend_data->ops.root_change == NULL) {
// deinit/reinit backend and free up resources if the backend
// cannot handle root change
destroy_backend(ps);
}
free_paint(ps, &ps->tgt_buffer);
}
ps->root_width = r->width;
@ -681,7 +633,6 @@ void configure_root(session_t *ps) {
free(r);
rebuild_screen_reg(ps);
invalidate_reg_ignore(ps);
// Whether a window is fullscreen depends on the new screen
// size. So we need to refresh the fullscreen state of all
@ -693,39 +644,28 @@ void configure_root(session_t *ps) {
}
}
if (ps->redirected) {
for (int i = 0; i < ps->damage_ring.count; i++) {
pixman_region32_clear(&ps->damage_ring.damages[i]);
}
ps->damage_ring.cursor = ps->damage_ring.count - 1;
#ifdef CONFIG_OPENGL
// GLX root change callback
if (BKEND_GLX == ps->o.legacy_backend && ps->o.use_legacy_backends) {
glx_on_root_change(ps);
}
#endif
if (has_root_change) {
if (ps->backend_data != NULL) {
ps->backend_data->ops.root_change(ps->backend_data, ps);
}
// Old backend's root_change is not a specific function
} else {
if (!initialize_backend(ps)) {
log_fatal("Failed to re-initialize backend after root "
"change, aborting...");
ps->quit = true;
/* TODO(yshui) only event handlers should request
* ev_break, otherwise it's too hard to keep track of what
* can break the event loop */
ev_break(ps->loop, EVBREAK_ALL);
return;
}
// Re-acquire the root pixmap.
root_damaged(ps);
}
force_repaint(ps);
if (!ps->redirected) {
return;
}
if (ps->backend_data != NULL) {
ps->backend_data->ops.root_change(ps->backend_data, ps);
} else {
if (!initialize_backend(ps)) {
log_fatal("Failed to re-initialize backend after root "
"change, aborting...");
ps->quit = true;
/* TODO(yshui) only event handlers should request
* ev_break, otherwise it's too hard to keep track of what
* can break the event loop */
ev_break(ps->loop, EVBREAK_ALL);
return;
}
// Re-acquire the root pixmap.
root_damaged(ps);
}
force_repaint(ps);
}
/**
@ -749,21 +689,10 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
continue;
}
const winmode_t mode_old = w->mode;
const bool was_painted = w->to_paint;
if (w->running_animation_instance != NULL) {
*animation = true;
}
// Add window to damaged area if its opacity changes
// If was_painted == false, and to_paint is also false, we don't care
// If was_painted == false, but to_paint is true, damage will be added in
// the loop below
if (was_painted && w->running_animation_instance != NULL) {
add_damage_from_win(ps, w);
}
if (win_has_frame(w)) {
w->frame_opacity = ps->o.frame_opacity;
} else {
@ -772,21 +701,13 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
// Update window mode
w->mode = win_calc_mode(w);
// Destroy all reg_ignore above when frame opaque state changes on
// SOLID mode
if (was_painted && w->mode != mode_old) {
w->reg_ignore_valid = false;
}
}
// Opacity will not change, from now on.
rc_region_t *last_reg_ignore = rc_region_new();
// Opacity will not change, from this point onwards.
bool unredir_possible = false;
// Track whether it's the highest window to paint
bool is_highest = true;
bool reg_ignore_valid = true;
wm_stack_foreach_safe(ps->wm, cursor, next_cursor) {
__label__ skip_window;
auto w = wm_ref_deref(cursor);
@ -796,7 +717,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
bool to_paint = true;
// w->to_paint remembers whether this window is painted last time
const bool was_painted = w->to_paint;
const double window_opacity = win_animatable_get(w, WIN_SCRIPT_OPACITY);
const double blur_opacity = win_animatable_get(w, WIN_SCRIPT_BLUR_OPACITY);
auto window_options = win_options(w);
@ -805,15 +725,9 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
HASH_FIND_STR(ps->shaders, window_options.shader, fg_shader);
}
if (fg_shader != NULL && fg_shader->attributes & SHADER_ATTRIBUTE_ANIMATED) {
add_damage_from_win(ps, w);
*animation = true;
}
// Destroy reg_ignore if some window above us invalidated it
if (!reg_ignore_valid) {
rc_region_unref(&w->reg_ignore);
}
// log_trace("%d %d %s", w->a.map_state, w->ever_damaged, w->name);
log_trace("Checking whether window %#010x (%s) should be painted",
win_id(w), w->name);
@ -855,13 +769,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
// log_trace("%s %d %d %d", w->name, to_paint, w->opacity,
// w->paint_excluded);
// Add window to damaged area if its painting status changes
// or opacity changes
if (to_paint != was_painted) {
w->reg_ignore_valid = false;
add_damage_from_win(ps, w);
}
// to_paint will never change after this point
if (!to_paint) {
log_trace("|- will not be painted");
@ -871,33 +778,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
log_trace("|- will be painted");
log_verbose("Window %#010x (%s) will be painted", win_id(w), w->name);
// Generate ignore region for painting to reduce GPU load
if (!w->reg_ignore) {
w->reg_ignore = rc_region_ref(last_reg_ignore);
}
// If the window is solid, or we enabled clipping for transparent windows,
// we add the window region to the ignored region
// Otherwise last_reg_ignore shouldn't change
if ((w->mode != WMODE_TRANS && !ps->o.force_win_blend) ||
window_options.transparent_clipping) {
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
region_t *tmp = rc_region_new();
if (w->mode == WMODE_SOLID) {
*tmp =
win_get_bounding_shape_global_without_corners_by_val(w);
} else {
// w->mode == WMODE_FRAME_TRANS
win_get_region_noframe_local_without_corners(w, tmp);
pixman_region32_intersect(tmp, tmp, &w->bounding_shape);
pixman_region32_translate(tmp, w->g.x, w->g.y);
}
pixman_region32_union(tmp, tmp, last_reg_ignore);
rc_region_unref(&last_reg_ignore);
last_reg_ignore = tmp;
}
// (Un)redirect screen
// We could definitely unredirect the screen when there's no window to
// paint, but this is typically unnecessary, may cause flickering when
@ -931,9 +811,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
}
skip_window:
reg_ignore_valid = reg_ignore_valid && w->reg_ignore_valid;
w->reg_ignore_valid = true;
if (w->state == WSTATE_DESTROYED && w->running_animation_instance == NULL) {
// the window should be destroyed because it was destroyed
// by X server and now its animations are finished
@ -947,8 +824,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
}
}
rc_region_unref(&last_reg_ignore);
// If possible, unredirect all windows and stop painting
if (ps->o.redirected_force != UNSET) {
unredir_possible = !ps->o.redirected_force;
@ -985,10 +860,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
}
void root_damaged(session_t *ps) {
if (ps->root_tile_paint.pixmap) {
free_root_tile(ps);
}
if (!ps->redirected) {
return;
}
@ -1043,13 +914,14 @@ void root_damaged(session_t *ps) {
force_repaint(ps);
}
/**
* Force a full-screen repaint.
*/
/// Force a full-screen repaint.
void force_repaint(session_t *ps) {
assert(pixman_region32_not_empty(&ps->screen_reg));
// `layout_manager` might be NULL if the screen is not redirected, if a render is
// started in this case it will always be a full-screen render.
if (ps->layout_manager != NULL) {
layout_manager_clear(ps->layout_manager);
}
queue_redraw(ps);
add_damage(ps, &ps->screen_reg);
}
/**
@ -1288,10 +1160,9 @@ uint8_t session_redirection_mode(session_t *ps) {
if (ps->o.debug_mode) {
// If the backend is not rendering to the screen, we don't need to
// take over the screen.
assert(!ps->o.use_legacy_backends);
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
}
if (!ps->o.use_legacy_backends && !backend_can_present(ps->o.backend)) {
if (!backend_can_present(ps->o.backend)) {
// if the backend doesn't render anything, we don't need to take over the
// screen.
return XCB_COMPOSITE_REDIRECT_AUTOMATIC;
@ -1328,25 +1199,12 @@ static bool redirect_start(session_t *ps) {
return false;
}
if (!ps->o.use_legacy_backends) {
assert(ps->backend_data);
ps->damage_ring.count =
ps->backend_data->ops.max_buffer_age(ps->backend_data);
ps->layout_manager = layout_manager_new((unsigned)ps->damage_ring.count);
} else {
ps->damage_ring.count = maximum_buffer_age(ps);
}
ps->damage_ring.damages = ccalloc(ps->damage_ring.count, region_t);
ps->damage_ring.cursor = ps->damage_ring.count - 1;
for (int i = 0; i < ps->damage_ring.count; i++) {
pixman_region32_init(&ps->damage_ring.damages[i]);
}
assert(ps->backend_data);
auto damage_count = ps->backend_data->ops.max_buffer_age(ps->backend_data);
ps->layout_manager = layout_manager_new((unsigned)damage_count);
ps->frame_pacing = ps->o.frame_pacing && ps->o.vsync;
if ((ps->o.use_legacy_backends || ps->o.benchmark ||
!ps->backend_data->ops.last_render_time) &&
ps->frame_pacing) {
if ((ps->o.benchmark || !ps->backend_data->ops.last_render_time) && ps->frame_pacing) {
// Disable frame pacing if we are using a legacy backend or if we are in
// benchmark mode, or if the backend doesn't report render time
log_info("Disabling frame pacing.");
@ -1415,14 +1273,6 @@ static void unredirect(session_t *ps) {
xcb_unmap_window(ps->c.c, ps->overlay);
}
// Free the damage ring
for (int i = 0; i < ps->damage_ring.count; ++i) {
pixman_region32_fini(&ps->damage_ring.damages[i]);
}
ps->damage_ring.count = 0;
free(ps->damage_ring.damages);
ps->damage_ring.cursor = 0;
ps->damage_ring.damages = NULL;
if (ps->layout_manager) {
layout_manager_free(ps->layout_manager);
ps->layout_manager = NULL;
@ -1607,7 +1457,7 @@ static void handle_new_windows(session_t *ps) {
case WM_TREE_CHANGE_TOPLEVEL_KILLED:
w = wm_ref_deref(wm_change.toplevel);
if (w != NULL) {
win_destroy_start(ps, w);
win_destroy_start(w);
} else {
// This window is not managed, no point keeping the zombie
// around.
@ -1630,7 +1480,7 @@ static void handle_new_windows(session_t *ps) {
}
ev_update_focused(ps);
break;
case WM_TREE_CHANGE_TOPLEVEL_RESTACKED: invalidate_reg_ignore(ps); break;
case WM_TREE_CHANGE_TOPLEVEL_RESTACKED: break;
default: unreachable();
}
}
@ -1794,8 +1644,13 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
w = wm_ref_toplevel_of(ps->wm, w);
auto win = w == NULL ? NULL : wm_ref_deref(w);
if (win != NULL) {
add_damage_from_win(ps, win);
if (win == NULL) {
region_t tmp;
pixman_region32_init(&tmp);
win_extents(win, &tmp);
pixman_region32_translate(&tmp, -win->g.x, -win->g.y);
pixman_region32_union(&win->damaged, &win->damaged, &tmp);
pixman_region32_fini(&tmp);
} else {
force_repaint(ps);
}
@ -1841,71 +1696,65 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
static int paint = 0;
log_verbose("Render start, frame %d", paint);
if (!ps->o.use_legacy_backends) {
uint64_t after_damage_us = 0;
now = get_time_timespec();
auto render_start_us =
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
if (ps->backend_data->ops.device_status &&
ps->backend_data->ops.device_status(ps->backend_data) !=
DEVICE_STATUS_NORMAL) {
log_error("Device reset detected");
// Wait for reset to complete
// Although ideally the backend should return
// DEVICE_STATUS_NORMAL after a reset is completed, it's
// not always possible.
//
// According to ARB_robustness (emphasis mine):
//
// "If a reset status other than NO_ERROR is returned
// and subsequent calls return NO_ERROR, the context
// reset was encountered and completed. If a reset
// status is repeatedly returned, the context **may**
// be in the process of resetting."
//
// Which means it may also not be in the process of
// resetting. For example on AMDGPU devices, Mesa OpenGL
// always return CONTEXT_RESET after a reset has started,
// completed or not.
//
// So here we blindly wait 5 seconds and hope ourselves
// best of the luck.
sleep(5);
log_info("Resetting picom after device reset");
reset_enable(ps->loop, NULL, 0);
return;
uint64_t after_damage_us = 0;
now = get_time_timespec();
auto render_start_us =
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
if (ps->backend_data->ops.device_status &&
ps->backend_data->ops.device_status(ps->backend_data) !=
DEVICE_STATUS_NORMAL) {
log_error("Device reset detected");
// Wait for reset to complete
// Although ideally the backend should return
// DEVICE_STATUS_NORMAL after a reset is completed, it's
// not always possible.
//
// According to ARB_robustness (emphasis mine):
//
// "If a reset status other than NO_ERROR is returned
// and subsequent calls return NO_ERROR, the context
// reset was encountered and completed. If a reset
// status is repeatedly returned, the context **may**
// be in the process of resetting."
//
// Which means it may also not be in the process of
// resetting. For example on AMDGPU devices, Mesa OpenGL
// always return CONTEXT_RESET after a reset has started,
// completed or not.
//
// So here we blindly wait 5 seconds and hope ourselves
// best of the luck.
sleep(5);
log_info("Resetting picom after device reset");
reset_enable(ps->loop, NULL, 0);
return;
}
layout_manager_append_layout(
ps->layout_manager, ps->wm, ps->root_image_generation,
(ivec2){.width = ps->root_width, .height = ps->root_height});
bool succeeded = renderer_render(
ps->renderer, ps->backend_data, ps->root_image, ps->layout_manager,
ps->command_builder, ps->backend_blur_context, render_start_us,
ps->sync_fence, ps->o.use_damage, ps->o.monitor_repaint,
ps->o.force_win_blend, ps->o.blur_background_frame,
ps->o.inactive_dim_fixed, ps->o.max_brightness,
ps->o.crop_shadow_to_monitor ? &ps->monitors : NULL, ps->shaders,
&after_damage_us);
if (!succeeded) {
log_fatal("Render failure");
abort();
}
did_render = true;
if (ps->next_render > 0) {
log_verbose("Render schedule deviation: %ld us (%s) %" PRIu64
" %" PRIu64,
labs((long)after_damage_us - (long)ps->next_render),
after_damage_us < ps->next_render ? "early" : "late",
after_damage_us, ps->next_render);
ps->last_schedule_delay = 0;
if (after_damage_us > ps->next_render) {
ps->last_schedule_delay = after_damage_us - ps->next_render;
}
layout_manager_append_layout(
ps->layout_manager, ps->wm, ps->root_image_generation,
(ivec2){.width = ps->root_width, .height = ps->root_height});
bool succeeded = renderer_render(
ps->renderer, ps->backend_data, ps->root_image, ps->layout_manager,
ps->command_builder, ps->backend_blur_context, render_start_us,
ps->sync_fence, ps->o.use_damage, ps->o.monitor_repaint,
ps->o.force_win_blend, ps->o.blur_background_frame,
ps->o.inactive_dim_fixed, ps->o.max_brightness,
ps->o.crop_shadow_to_monitor ? &ps->monitors : NULL,
ps->shaders, &after_damage_us);
if (!succeeded) {
log_fatal("Render failure");
abort();
}
did_render = true;
if (ps->next_render > 0) {
log_verbose(
"Render schedule deviation: %ld us (%s) %" PRIu64
" %" PRIu64,
labs((long)after_damage_us - (long)ps->next_render),
after_damage_us < ps->next_render ? "early" : "late",
after_damage_us, ps->next_render);
ps->last_schedule_delay = 0;
if (after_damage_us > ps->next_render) {
ps->last_schedule_delay =
after_damage_us - ps->next_render;
}
}
} else {
paint_all(ps, bottom);
}
log_verbose("Render end");
@ -2071,21 +1920,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.root_width = 0,
// .root_damage = XCB_NONE,
.overlay = XCB_NONE,
.root_tile_fill = false,
.root_tile_paint = PAINT_INIT,
.tgt_picture = XCB_NONE,
.tgt_buffer = PAINT_INIT,
.reg_win = XCB_NONE,
#ifdef CONFIG_OPENGL
.glx_prog_win = GLX_PROG_MAIN_INIT,
#endif
.redirected = false,
.alpha_picts = NULL,
.fade_time = 0L,
.quit = false,
.expose_rects = NULL,
.black_picture = XCB_NONE,
.cshadow_picture = XCB_NONE,
.white_picture = XCB_NONE,
@ -2093,10 +1933,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.last_msc = 0,
#ifdef CONFIG_VSYNC_DRM
.drm_fd = -1,
#endif
.xfixes_event = 0,
.xfixes_error = 0,
.damage_event = 0,
@ -2115,7 +1951,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.glx_exists = false,
.glx_event = 0,
.glx_error = 0,
.xrfilter_convolution_exists = false,
#ifdef CONFIG_DBUS
.dbus_data = NULL,
@ -2210,9 +2045,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
XCB_XFIXES_MINOR_VERSION)
.sequence);
ps->damage_ring.x_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damage_ring.x_region,
0, NULL)) {
ps->x_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->x_region, 0, NULL)) {
log_fatal("Failed to create a XFixes region");
goto err;
}
@ -2308,12 +2142,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
}
if (ps->o.use_legacy_backends) {
ps->shadow_context =
(void *)gaussian_kernel_autodetect_deviation(ps->o.shadow_radius);
sum_kernel_preprocess((conv *)ps->shadow_context);
}
// Query X Shape
ext_info = xcb_get_extension_data(ps->c.c, &xcb_shape_id);
if (ext_info && ext_info->present) {
@ -2428,14 +2256,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
}
if (bkend_use_glx(ps) && ps->o.use_legacy_backends) {
auto gl_logger = gl_string_marker_logger_new();
if (gl_logger) {
log_info("Enabling gl string marker");
log_add_target_tls(gl_logger);
}
}
// Monitor screen changes if vsync_sw is enabled and we are using
// an auto-detected refresh rate, or when X RandR features are enabled
if (ps->randr_exists) {
@ -2444,23 +2264,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
x_update_monitors_async(&ps->c, &ps->monitors);
}
{
xcb_render_create_picture_value_list_t pa = {
.subwindowmode = IncludeInferiors,
};
ps->root_picture = x_create_picture_with_visual_and_pixmap(
&ps->c, ps->c.screen_info->root_visual, ps->c.screen_info->root,
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
if (ps->overlay != XCB_NONE) {
ps->tgt_picture = x_create_picture_with_visual_and_pixmap(
&ps->c, ps->c.screen_info->root_visual, ps->overlay,
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
} else {
ps->tgt_picture = ps->root_picture;
}
}
ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->c.dpy), EV_READ);
ev_io_start(ps->loop, &ps->xiow);
ev_init(&ps->unredir_timer, tmout_unredir_callback);
@ -2510,7 +2313,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
wm_import_start(ps->wm, &ps->c, ps->atoms, ps->c.screen_info->root, NULL);
ps->command_builder = command_builder_new();
ps->expose_rects = dynarr_new(rect_t, 0);
// wm_complete_import will set event masks on the root window, but its event
// mask is missing things we need, so we need to set it again.
@ -2538,12 +2340,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
free(r);
rebuild_screen_reg(ps);
// Initialize filters, must be preceded by OpenGL context creation
if (ps->o.use_legacy_backends && !init_render(ps)) {
log_fatal("Failed to initialize the backend");
exit(1);
}
if (session_redirection_mode(ps) == XCB_COMPOSITE_REDIRECT_MANUAL && compositor_running) {
// Don't take the overlay when there is another compositor
// running, so we don't disrupt it.
@ -2582,7 +2378,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// The old backends doesn't have a automatic redirection mode
log_info("The compositor is started in automatic redirection mode.");
assert(!ps->o.use_legacy_backends);
if (backend_can_present(ps->o.backend)) {
// If the backend has `present`, we couldn't be in automatic
@ -2652,21 +2447,7 @@ static void session_destroy(session_t *ps) {
options_destroy(&ps->o);
c2_state_free(ps->c2_state);
// Free tgt_{buffer,picture} and root_picture
if (ps->tgt_buffer.pict == ps->tgt_picture) {
ps->tgt_buffer.pict = XCB_NONE;
}
if (ps->tgt_picture != ps->root_picture) {
x_free_picture(&ps->c, ps->tgt_picture);
}
x_free_picture(&ps->c, ps->root_picture);
ps->tgt_picture = ps->root_picture = XCB_NONE;
free_paint(ps, &ps->tgt_buffer);
pixman_region32_fini(&ps->screen_reg);
dynarr_free_pod(ps->expose_rects);
x_free_monitor_info(&ps->monitors);
@ -2683,14 +2464,6 @@ static void session_destroy(session_t *ps) {
free(shader);
}
#ifdef CONFIG_VSYNC_DRM
// Close file opened for DRM VSync
if (ps->drm_fd >= 0) {
close(ps->drm_fd);
ps->drm_fd = -1;
}
#endif
// Release overlay window
if (ps->overlay && session_redirection_mode(ps) == XCB_COMPOSITE_REDIRECT_MANUAL) {
xcb_composite_release_overlay_window(ps->c.c, ps->overlay);
@ -2713,31 +2486,17 @@ static void session_destroy(session_t *ps) {
ps->debug_window = XCB_NONE;
}
if (ps->damage_ring.x_region != XCB_NONE) {
xcb_xfixes_destroy_region(ps->c.c, ps->damage_ring.x_region);
ps->damage_ring.x_region = XCB_NONE;
if (ps->x_region != XCB_NONE) {
xcb_xfixes_destroy_region(ps->c.c, ps->x_region);
ps->x_region = XCB_NONE;
}
if (!ps->o.use_legacy_backends) {
// backend is deinitialized in unredirect()
assert(ps->backend_data == NULL);
} else {
deinit_render(ps);
}
#if CONFIG_OPENGL
if (glx_has_context(ps)) {
// GLX context created, but not for rendering
glx_destroy(ps);
}
#endif
// backend is deinitialized in unredirect()
assert(ps->backend_data == NULL);
// Flush all events
xcb_aux_sync(ps->c.c);
ev_io_stop(ps->loop, &ps->xiow);
if (ps->o.use_legacy_backends) {
free_conv((conv *)ps->shadow_context);
}
destroy_atoms(ps->atoms);
#ifdef DEBUG_XRC

View file

@ -20,15 +20,12 @@
#include "config.h"
#include "log.h" // XXX clean up
#include "region.h"
#include "render.h"
#include "wm/win.h"
#include "x.h"
// == Functions ==
// TODO(yshui) move static inline functions that are only used in picom.c, into picom.c
void add_damage(session_t *ps, const region_t *damage);
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
void root_damaged(session_t *ps);

View file

@ -15,8 +15,6 @@ typedef struct pixman_box32 pixman_box32_t;
typedef pixman_region32_t region_t;
typedef pixman_box32_t rect_t;
RC_TYPE(region_t, rc_region, pixman_region32_init, pixman_region32_fini, static inline)
static inline void region_free(region_t *region) {
if (region) {
pixman_region32_fini(region);

File diff suppressed because it is too large Load diff

View file

@ -1,47 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <stdbool.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
#ifdef CONFIG_OPENGL
#include "backend/gl/glx.h"
#endif
#include "region.h"
typedef struct _glx_texture glx_texture_t;
typedef struct glx_prog_main glx_prog_main_t;
typedef struct session session_t;
struct win;
typedef struct paint {
xcb_pixmap_t pixmap;
xcb_render_picture_t pict;
glx_texture_t *ptex;
#ifdef CONFIG_OPENGL
struct glx_fbconfig_info fbcfg;
#endif
} paint_t;
typedef struct clip {
xcb_render_picture_t pict;
int x;
int y;
} clip_t;
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw,
int fullh, double opacity, bool argb, bool neg, unsigned int cr,
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
const glx_prog_main_t *pprogram, clip_t *clip);
void paint_all(session_t *ps, struct win *const t);
void free_paint(session_t *ps, paint_t *ppaint);
void free_root_tile(session_t *ps);
bool init_render(session_t *ps);
void deinit_render(session_t *ps);
int maximum_buffer_age(session_t *);

View file

@ -130,29 +130,46 @@ static void layer_init(struct layer *layer) {
}
static void layout_deinit(struct layout *layout) {
dynarr_free(layout->layers, layer_deinit);
dynarr_clear(layout->layers, layer_deinit);
command_builder_command_list_free(layout->commands);
*layout = (struct layout){};
layout->number_of_commands = 0;
layout->root_image_generation = 0;
layout->size = (ivec2){};
layout->first_layer_start = 0;
layout->commands = NULL;
}
struct layout_manager *layout_manager_new(unsigned max_buffer_age) {
struct layout_manager *planner = malloc(
sizeof(struct layout_manager) + (max_buffer_age + 1) * sizeof(struct layout));
planner->max_buffer_age = max_buffer_age + 1;
planner->current = 0;
planner->layer_indices = NULL;
list_init_head(&planner->free_indices);
pixman_region32_init(&planner->scratch_region);
struct layout_manager *lm = malloc(sizeof(struct layout_manager) +
(max_buffer_age + 1) * sizeof(struct layout));
lm->max_buffer_age = max_buffer_age + 1;
lm->current = 0;
lm->layer_indices = NULL;
list_init_head(&lm->free_indices);
pixman_region32_init(&lm->scratch_region);
for (unsigned i = 0; i <= max_buffer_age; i++) {
planner->layouts[i] = (struct layout){};
planner->layouts[i].layers = dynarr_new(struct layer, 5);
lm->layouts[i] = (struct layout){};
lm->layouts[i].layers = dynarr_new(struct layer, 5);
}
return planner;
return lm;
}
void layout_manager_clear(struct layout_manager *lm) {
for (unsigned i = 0; i < lm->max_buffer_age; i++) {
layout_deinit(&lm->layouts[i]);
}
struct layer_index *index, *tmp;
HASH_ITER(hh, lm->layer_indices, index, tmp) {
HASH_DEL(lm->layer_indices, index);
list_insert_after(&lm->free_indices, &index->free_list);
}
lm->current = 0;
}
void layout_manager_free(struct layout_manager *lm) {
for (unsigned i = 0; i < lm->max_buffer_age; i++) {
layout_deinit(&lm->layouts[i]);
dynarr_free(lm->layouts[i].layers, layer_deinit);
}
struct layer_index *index, *tmp;
HASH_ITER(hh, lm->layer_indices, index, tmp) {

View file

@ -90,6 +90,9 @@ void layout_manager_append_layout(struct layout_manager *lm, struct wm *wm,
/// layout.
struct layout *layout_manager_layout(struct layout_manager *lm, unsigned age);
void layout_manager_free(struct layout_manager *lm);
/// Clear all layouts in the layout manager, so that the next render will start from
/// scratch instead of incremental based on damage information.
void layout_manager_clear(struct layout_manager *lm);
/// Create a new render lm with a ring buffer for `max_buffer_age` layouts.
struct layout_manager *layout_manager_new(unsigned max_buffer_age);
/// Collect damage from the window for the past `buffer_age` frames.

View file

@ -136,8 +136,9 @@ static inline void dynarr_remove_swap_impl(size_t size, void *arr, size_t idx) {
#define dynarr_truncate(arr, n, dtor) \
do { \
if ((dtor) != NULL) { \
for (size_t i = n; i < dynarr_len(arr); i++) { \
(dtor)((arr) + i); \
for (size_t __dynarr_i = n; __dynarr_i < dynarr_len(arr); \
__dynarr_i++) { \
(dtor)((arr) + __dynarr_i); \
} \
} \
dynarr_len(arr) = n; \

View file

@ -340,60 +340,6 @@ allocchk_(const char *func_name, const char *file, unsigned int line, void *ptr)
((__typeof__(ptr))allocchk(realloc((ptr), (size_t)tmp * sizeof(*(ptr))))); \
})
/// RC_TYPE generates a reference counted type from `type`
///
/// parameters:
/// name = the generated type will be called `name`_t.
/// ctor = the constructor of `type`, will be called when
/// a value of `type` is created. should take one
/// argument of `type *`.
/// dtor = the destructor. will be called when all reference
/// is gone. has same signature as ctor
/// Q = function qualifier. this is the qualifier that
/// will be put before generated functions
//
/// functions generated:
/// `name`_new: create a new reference counted object of `type`
/// `name`_ref: increment the reference counter, return a
/// reference to the object
/// `name`_unref: decrement the reference counter. take a `type **`
/// because it needs to nullify the reference.
#define RC_TYPE(type, name, ctor, dtor, Q) \
typedef struct { \
type inner; \
int ref_count; \
} name##_internal_t; \
typedef type name##_t; \
Q type *name##_new(void) { \
name##_internal_t *ret = cmalloc(name##_internal_t); \
ctor((type *)ret); \
ret->ref_count = 1; \
return (type *)ret; \
} \
Q type *name##_ref(type *a) { \
__auto_type b = (name##_internal_t *)a; \
b->ref_count++; \
return a; \
} \
Q void name##_unref(type **a) { \
__auto_type b = (name##_internal_t *)*a; \
if (!b) \
return; \
b->ref_count--; \
if (!b->ref_count) { \
dtor((type *)b); \
free(b); \
} \
*a = NULL; \
}
/// Generate prototypes for functions generated by RC_TYPE
#define RC_TYPE_PROTO(type, name) \
typedef type name##_t; \
type *name##_new(void); \
void name##_ref(type *a); \
void name##_unref(type **a);
static inline void free_charpp(char **str) {
if (str) {
free(*str);

View file

@ -1,208 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
/// Function pointers to init VSync modes.
#include "common.h"
#include "log.h"
#ifdef CONFIG_OPENGL
#include "backend/gl/glx.h"
#include "opengl.h"
#endif
#ifdef CONFIG_VSYNC_DRM
#include <drm.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include "config.h"
#include "vsync.h"
#ifdef CONFIG_VSYNC_DRM
/**
* Wait for next VSync, DRM method.
*
* Stolen from:
* https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp
*/
static int vsync_drm_wait(session_t *ps) {
int ret = -1;
drm_wait_vblank_t vbl;
vbl.request.type = _DRM_VBLANK_RELATIVE, vbl.request.sequence = 1;
do {
ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl);
vbl.request.type &= ~(uint)_DRM_VBLANK_RELATIVE;
} while (ret && errno == EINTR);
if (ret)
log_error("VBlank ioctl did not work, unimplemented in this drmver?");
return ret;
}
/**
* Initialize DRM VSync.
*
* @return true for success, false otherwise
*/
static bool vsync_drm_init(session_t *ps) {
// Should we always open card0?
if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) {
log_error("Failed to open device.");
return false;
}
if (vsync_drm_wait(ps))
return false;
return true;
}
#endif
#ifdef CONFIG_OPENGL
/**
* Initialize OpenGL VSync.
*
* Stolen from:
* http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e
* Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html
*
* @return true for success, false otherwise
*/
static bool vsync_opengl_init(session_t *ps) {
if (!ensure_glx_context(ps)) {
return false;
}
return glxext.has_GLX_SGI_video_sync;
}
static bool vsync_opengl_oml_init(session_t *ps) {
if (!ensure_glx_context(ps)) {
return false;
}
return glxext.has_GLX_OML_sync_control;
}
static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) {
if (glxext.has_GLX_MESA_swap_control) {
return glXSwapIntervalMESA((uint)interval) == 0;
}
if (glxext.has_GLX_SGI_swap_control) {
return glXSwapIntervalSGI(interval) == 0;
}
if (glxext.has_GLX_EXT_swap_control) {
GLXDrawable d = glXGetCurrentDrawable();
if (d == None) {
// We don't have a context??
return false;
}
glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval);
return true;
}
return false;
}
static bool vsync_opengl_swc_init(session_t *ps) {
if (!bkend_use_glx(ps)) {
log_error("OpenGL swap control requires the GLX backend.");
return false;
}
if (!vsync_opengl_swc_swap_interval(ps, 1)) {
log_error("Failed to load a swap control extension.");
return false;
}
return true;
}
/**
* Wait for next VSync, OpenGL method.
*/
static int vsync_opengl_wait(session_t *ps attr_unused) {
unsigned vblank_count = 0;
glXGetVideoSyncSGI(&vblank_count);
glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
return 0;
}
/**
* Wait for next VSync, OpenGL OML method.
*
* https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html
*/
static int vsync_opengl_oml_wait(session_t *ps) {
int64_t ust = 0, msc = 0, sbc = 0;
glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc);
glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
return 0;
}
#endif
/**
* Initialize current VSync method.
*/
bool vsync_init(session_t *ps) {
#ifdef CONFIG_OPENGL
if (bkend_use_glx(ps)) {
// Mesa turns on swap control by default, undo that
vsync_opengl_swc_swap_interval(ps, 0);
}
#endif
#ifdef CONFIG_VSYNC_DRM
log_warn("The DRM vsync method is deprecated, please don't enable it.");
#endif
if (!ps->o.vsync) {
return true;
}
#ifdef CONFIG_OPENGL
if (bkend_use_glx(ps)) {
if (!vsync_opengl_swc_init(ps)) {
return false;
}
ps->vsync_wait = NULL; // glXSwapBuffers will automatically wait
// for vsync, we don't need to do anything.
return true;
}
#endif
// Oh no, we are not using glx backend.
// Throwing things at wall.
#ifdef CONFIG_OPENGL
if (vsync_opengl_oml_init(ps)) {
log_info("Using the opengl-oml vsync method");
ps->vsync_wait = vsync_opengl_oml_wait;
return true;
}
if (vsync_opengl_init(ps)) {
log_info("Using the opengl vsync method");
ps->vsync_wait = vsync_opengl_wait;
return true;
}
#endif
#ifdef CONFIG_VSYNC_DRM
if (vsync_drm_init(ps)) {
log_info("Using the drm vsync method");
ps->vsync_wait = vsync_drm_wait;
return true;
}
#endif
log_error("No supported vsync method found for this backend");
return false;
}

View file

@ -1,8 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <stdbool.h>
typedef struct session session_t;
bool vsync_init(session_t *ps);

View file

@ -52,9 +52,6 @@ enum win_flags {
WIN_FLAGS_PIXMAP_STALE = 1,
/// there was an error binding the window pixmap
WIN_FLAGS_PIXMAP_ERROR = 4,
/// Window is damaged, and should be added to the damage region
/// (only used by the legacy backends, remove)
WIN_FLAGS_DAMAGED = 8,
/// the client window needs to be updated
WIN_FLAGS_CLIENT_STALE = 32,
/// the window is mapped by X, we need to call map_win_start for it

View file

@ -28,7 +28,6 @@
#include "log.h"
#include "picom.h"
#include "region.h"
#include "render.h"
#include "utils/console.h"
#include "utils/misc.h"
#include "x.h"
@ -181,25 +180,6 @@ void win_get_region_frame_local(const struct win *w, region_t *res) {
gen_by_val(win_get_region_frame_local);
/**
* Add a window to damaged area.
*
* @param ps current session
* @param w struct _win element representing the window
*/
void add_damage_from_win(session_t *ps, const struct win *w) {
// XXX there was a cached extents region, investigate
// if that's better
// TODO(yshui) use the bounding shape when the window is shaped, otherwise the
// damage would be excessive
region_t extents;
pixman_region32_init(&extents);
win_extents(w, &extents);
add_damage(ps, &extents);
pixman_region32_fini(&extents);
}
/// Release the images attached to this window
static inline void win_release_pixmap(backend_t *base, struct win *w) {
log_debug("Releasing pixmap of window %#010x (%s)", win_id(w), w->name);
@ -310,8 +290,7 @@ static void win_update_properties(session_t *ps, struct win *w) {
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_FRAME_EXTENTS)) {
auto client_win = win_client_id(w, /*fallback_to_self=*/false);
win_update_frame_extents(&ps->c, ps->atoms, w, client_win, ps->o.frame_opacity);
add_damage_from_win(ps, w);
win_update_frame_extents(&ps->c, ps->atoms, w, client_win);
}
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_NAME) ||
@ -397,12 +376,6 @@ void win_process_primary_flags(session_t *ps, struct win *w) {
//
// All that is basically me saying what really matters is if the
// window was rendered last frame, not if it's mapped in X server.
if (w->to_paint) {
// Mark the old extents of this window as damaged. The new
// extents will be marked damaged below, after the window
// extents are updated.
add_damage_from_win(ps, w);
}
// Update window geometry
w->previous.g = w->g;
@ -420,19 +393,15 @@ void win_process_primary_flags(session_t *ps, struct win *w) {
// Window shape/size changed, invalidate the images we built
// log_trace("free out dated pict");
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE |
WIN_FLAGS_FACTOR_CHANGED | WIN_FLAGS_DAMAGED);
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_FACTOR_CHANGED);
win_release_mask(ps->backend_data, w);
win_release_shadow(ps->backend_data, w);
ps->pending_updates = true;
free_paint(ps, &w->paint);
free_paint(ps, &w->shadow_paint);
}
if (win_check_flags_all(w, WIN_FLAGS_POSITION_STALE)) {
win_clear_flags(w, WIN_FLAGS_POSITION_STALE);
win_set_flags(w, WIN_FLAGS_DAMAGED);
}
}
@ -495,12 +464,6 @@ void win_process_secondary_flags(session_t *ps, struct win *w) {
win_on_factor_change(ps, w);
win_clear_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
if (win_check_flags_all(w, WIN_FLAGS_DAMAGED)) {
// Add damage, has to be done last so the window has the latest geometry
// information.
add_damage_from_win(ps, w);
win_clear_flags(w, WIN_FLAGS_DAMAGED);
}
auto new_options = win_options(w);
if (win_options_no_damage(&old_options, &new_options)) {
@ -508,9 +471,7 @@ void win_process_secondary_flags(session_t *ps, struct win *w) {
return;
}
add_damage_from_win(ps, w); // Only for legacy backends
if (new_options.shadow != old_options.shadow && !new_options.shadow) {
add_damage(ps, &extents);
win_release_shadow(ps->backend_data, w);
}
pixman_region32_fini(&extents);
@ -787,8 +748,6 @@ static double win_calc_opacity_target(session_t *ps, const struct win *w, bool f
/// Finish the unmapping of a window (e.g. after fading has finished).
/// Doesn't free `w`
void unmap_win_finish(session_t *ps, struct win *w) {
w->reg_ignore_valid = false;
// We are in unmap_win, this window definitely was viewable
if (ps->backend_data) {
// Only the pixmap needs to be freed and reacquired when mapping.
@ -799,9 +758,6 @@ void unmap_win_finish(session_t *ps, struct win *w) {
assert(!w->shadow_image);
}
free_paint(ps, &w->paint);
free_paint(ps, &w->shadow_paint);
// Try again at binding images when the window is mapped next time
if (w->state != WSTATE_DESTROYED) {
win_clear_flags(w, WIN_FLAGS_PIXMAP_ERROR);
@ -1131,7 +1087,6 @@ void win_on_factor_change(session_t *ps, struct win *w) {
w->mode = win_calc_mode(w);
log_debug("Window mode changed to %d", w->mode);
w->reg_ignore_valid = false;
if (ps->debug_window != XCB_NONE &&
(win_id(w) == ps->debug_window ||
(win_client_id(w, /*fallback_to_self=*/false) == ps->debug_window))) {
@ -1212,7 +1167,7 @@ void win_on_client_update(session_t *ps, struct win *w) {
xcb_window_t client_win_id = win_client_id(w, /*fallback_to_self=*/true);
// Get frame widths. The window is in damaged area already.
win_update_frame_extents(&ps->c, ps->atoms, w, client_win_id, ps->o.frame_opacity);
win_update_frame_extents(&ps->c, ps->atoms, w, client_win_id);
// Get window group
if (ps->o.track_leader) {
@ -1239,24 +1194,10 @@ void win_on_client_update(session_t *ps, struct win *w) {
free(r);
}
#ifdef CONFIG_OPENGL
void free_win_res_glx(session_t *ps, struct win *w);
#else
static inline void free_win_res_glx(session_t * /*ps*/, struct win * /*w*/) {
}
#endif
/**
* Free all resources in a <code>struct _win</code>.
*/
void free_win_res(session_t *ps, struct win *w) {
// No need to call backend release_image here because
// finish_unmap_win should've done that for us.
// XXX unless we are called by session_destroy
// assert(w->win_data == NULL);
free_win_res_glx(ps, w);
free_paint(ps, &w->paint);
free_paint(ps, &w->shadow_paint);
// Above should be done during unmapping
// Except when we are called by session_destroy
@ -1264,7 +1205,6 @@ void free_win_res(session_t *ps, struct win *w) {
pixman_region32_fini(&w->bounding_shape);
// BadDamage may be thrown if the window is destroyed
x_set_error_action_ignore(&ps->c, xcb_damage_destroy(ps->c.c, w->damage));
rc_region_unref(&w->reg_ignore);
free(w->name);
free(w->class_instance);
free(w->class_general);
@ -1293,9 +1233,6 @@ struct win *win_maybe_allocate(session_t *ps, struct wm_ref *cursor,
.opacity_set = 1,
.frame_extents = MARGIN_INIT,
.prop_shadow = -1,
.paint = PAINT_INIT,
.shadow_paint = PAINT_INIT,
};
// Reject overlay window
@ -1575,7 +1512,7 @@ void win_update_bounding_shape(struct x_connection *c, struct win *w, bool shape
* Retrieve frame extents from a window.
*/
void win_update_frame_extents(struct x_connection *c, struct atom *atoms, struct win *w,
xcb_window_t client, double frame_opacity) {
xcb_window_t client) {
if (client == XCB_NONE) {
w->frame_extents = (margin_t){0};
return;
@ -1598,20 +1535,10 @@ void win_update_frame_extents(struct x_connection *c, struct atom *atoms, struct
extents[i] = (int)prop.c32[i];
}
const bool changed = w->frame_extents.left != extents[0] ||
w->frame_extents.right != extents[1] ||
w->frame_extents.top != extents[2] ||
w->frame_extents.bottom != extents[3];
w->frame_extents.left = extents[0];
w->frame_extents.right = extents[1];
w->frame_extents.top = extents[2];
w->frame_extents.bottom = extents[3];
// If frame_opacity != 1, then frame of this window
// is not included in reg_ignore of underneath windows
if (frame_opacity == 1 && changed) {
w->reg_ignore_valid = false;
}
}
log_trace("(%#010x): %d, %d, %d, %d", win_id(w), w->frame_extents.left,
@ -1620,19 +1547,6 @@ void win_update_frame_extents(struct x_connection *c, struct atom *atoms, struct
free_winprop(&prop);
}
bool win_is_region_ignore_valid(session_t *ps, const struct win *w) {
wm_stack_foreach(ps->wm, cursor) {
auto i = wm_ref_deref(cursor);
if (i == w) {
break;
}
if (i != NULL && !i->reg_ignore_valid) {
return false;
}
}
return true;
}
/// Finish the destruction of a window (e.g. after fading has finished).
/// Frees `w`
void win_destroy_finish(session_t *ps, struct win *w) {
@ -1662,7 +1576,7 @@ void win_destroy_finish(session_t *ps, struct win *w) {
/// Start destroying a window. Windows cannot always be destroyed immediately
/// because of fading and such.
void win_destroy_start(session_t *ps, struct win *w) {
void win_destroy_start(struct win *w) {
BUG_ON(w == NULL);
log_debug("Destroying %#010x (%s)", win_id(w), w->name);
@ -1683,15 +1597,6 @@ void win_destroy_start(session_t *ps, struct win *w) {
// before changing the window state to destroying
win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE);
// If size/shape/position information is stale,
// win_process_update_flags will update them and add the new
// window extents to damage. Since the window has been destroyed,
// we cannot get the complete information at this point, so we
// just add what we currently have to the damage.
if (win_check_flags_any(w, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
add_damage_from_win(ps, w);
}
// Clear some flags about stale window information. Because now
// the window is destroyed, we can't update them anyway.
win_clear_flags(w, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE |

View file

@ -17,7 +17,6 @@
#include "config.h"
#include "defs.h"
#include "region.h"
#include "render.h"
#include "transition/script.h"
#include "utils/list.h"
#include "utils/misc.h"
@ -27,7 +26,6 @@
struct backend_base;
typedef struct session session_t;
typedef struct _glx_texture glx_texture_t;
struct wm_cursor;
#define wm_stack_foreach(wm, i) \
@ -42,20 +40,6 @@ struct wm_cursor;
*(next_i) = (i) != NULL ? wm_ref_below(i) : NULL; \
(i); (i) = (next_i), (next_i) = (i) != NULL ? wm_ref_below(i) : NULL)
#ifdef CONFIG_OPENGL
// FIXME this type should be in opengl.h
// it is very unideal for it to be here
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;
} glx_blur_cache_t;
#endif
struct wm;
/// An entry in the window stack. May or may not correspond to a window we know about.
struct window_stack_entry {
@ -141,8 +125,6 @@ struct win {
bool pixmap_damaged;
/// Damage of the window.
xcb_damage_damage_t damage;
/// Paint info of the window.
paint_t paint;
/// bitmap for properties which needs to be updated
uint64_t *stale_props;
/// number of uint64_ts that has been allocated for stale_props
@ -153,16 +135,6 @@ struct win {
region_t bounding_shape;
/// Window flags. Definitions above.
uint64_t flags;
/// The region of screen that will be obscured when windows above is painted,
/// in global coordinates.
/// We use this to reduce the pixels that needed to be paint when painting
/// this window and anything underneath. Depends on window frame
/// opacity state, window geometry, window mapped/unmapped state,
/// window mode of the windows above. DOES NOT INCLUDE the body of THIS WINDOW.
/// NULL means reg_ignore has not been calculated for this window.
rc_region_t *reg_ignore;
/// Whether the reg_ignore of all windows beneath this window are valid
bool reg_ignore_valid;
/// Cached width/height of the window including border.
int widthb, heightb;
/// Whether the window is bounding-shaped.
@ -231,23 +203,12 @@ struct win {
int shadow_width;
/// Height of shadow. Affected by window size and command line argument.
int shadow_height;
/// Picture to render shadow. Affected by window size.
paint_t shadow_paint;
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
/// none.
long long prop_shadow;
struct c2_window_state c2_state;
// Animation related
#ifdef CONFIG_OPENGL
/// Textures and FBO background blur use.
glx_blur_cache_t glx_blur_cache;
/// Background texture of the window
glx_texture_t *glx_texture_bg;
#endif
/// The damaged region of the window, in window local coordinates.
region_t damaged;
@ -417,7 +378,7 @@ void unmap_win_start(struct win *);
void unmap_win_finish(session_t *ps, struct win *w);
/// Start the destroying of a window. Windows cannot always be destroyed immediately
/// because of fading and such.
void win_destroy_start(session_t *ps, struct win *w);
void win_destroy_start(struct win *w);
void win_map_start(struct session *ps, struct win *w);
/// Release images bound with a window, set the *_NONE flags on the window. Only to be
/// used when de-initializing the backend outside of win.c
@ -449,13 +410,6 @@ bool win_is_bypassing_compositor(const session_t *ps, const struct win *w);
*/
void win_extents(const struct win *w, region_t *res);
region_t win_extents_by_val(const struct win *w);
/**
* Add a window to damaged area.
*
* @param ps current session
* @param w struct _win element representing the window
*/
void add_damage_from_win(session_t *ps, const struct win *w);
/**
* Get a rectangular region a window occupies, excluding frame and shadow.
*
@ -508,9 +462,6 @@ static inline xcb_window_t win_client_id(const struct win *w, bool fallback_to_s
return wm_ref_win_id(client_win);
}
/// check if reg_ignore_valid is true for all windows above us
bool attr_pure win_is_region_ignore_valid(session_t *ps, const struct win *w);
/// Whether a given window is mapped on the X server side
bool win_is_mapped_in_x(const struct win *w);
/// Set flags on a window. Some sanity checks are performed
@ -553,7 +504,7 @@ bool win_update_wintype(struct x_connection *c, struct atom *atoms, struct win *
* Retrieve frame extents from a window.
*/
void win_update_frame_extents(struct x_connection *c, struct atom *atoms, struct win *w,
xcb_window_t client, double frame_opacity);
xcb_window_t client);
/**
* Retrieve the <code>WM_CLASS</code> of a window and update its
* <code>win</code> structure.