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:
parent
2f917fda23
commit
a54adb62da
26 changed files with 258 additions and 4524 deletions
|
@ -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`
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
125
src/common.h
125
src/common.h
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
63
src/event.c
63
src/event.c
|
@ -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(®ion, rects, (int)nrects);
|
||||
add_damage(ps, ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
|
|
1544
src/opengl.c
1544
src/opengl.c
File diff suppressed because it is too large
Load diff
227
src/opengl.h
227
src/opengl.h
|
@ -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);
|
145
src/options.c
145
src/options.c
|
@ -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 != '/') {
|
||||
|
|
575
src/picom.c
575
src/picom.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
1544
src/render.c
1544
src/render.c
File diff suppressed because it is too large
Load diff
47
src/render.h
47
src/render.h
|
@ -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 *);
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -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);
|
||||
|
|
208
src/vsync.c
208
src/vsync.c
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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
|
||||
|
|
105
src/wm/win.c
105
src/wm/win.c
|
@ -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 |
|
||||
|
|
53
src/wm/win.h
53
src/wm/win.h
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue