Skip to content

Commit

Permalink
Merge remote-tracking branch 'yshui/next' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
FT-Labs committed Jan 22, 2024
2 parents 4299336 + 702e30d commit 2417084
Show file tree
Hide file tree
Showing 25 changed files with 1,204 additions and 364 deletions.
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Unreleased

## Bug fixes

* Fix missing fading on window close for some window managers. (#704)

# v11 (2024-Jan-20)

## Build changes

* Due to some caveats discovered related to setting the `CAP_SYS_NICE` capability, it is now recommended to **NOT** set this capability for picom.

## Deprecations

* Uses of `--sw-opti`, and `--respect-prop-shadow` are now hard errors.
* `-F` has been removed completely. It was deprecated before the picom fork.

# v11-rc1 (2024-Jan-14)

## Notable features

* picom now uses dithering to prevent banding. Banding is most notable when using a strong background blur. (#952)
* Frame pacing. picom uses present feedback information to schedule new frames when it makes sense to do so. This improves latency, and replaces the `glFlush` and `GL_MaxFramesAllowed=1` hacks we used to do for NVIDIA. (#968 #1156)
* Some missing features have been implemented for the EGL backend (#1004 #1007)

## Bug fixes

* Many memory/resource leak fixes thanks to @absolutelynothelix . (#977 #978 #979 #980 #982 #985 #992 #1009 #1022)
* Fix tiling of wallpaper. (#1002)
* Fix some blur artifacts (#1095)
* Fix shadow color for transparent shadows (#1124)
* Don't spam logs when another compositor is running (#1104)
* Fix rounded corners showing as black with the xrender backend (#1003)
* Fix blur with rounded windows (#950)

## Build changes

* Dependency `pcre` has been replaced by `pcre2`.
* New dependency `xcb-util`.
* `xinerama` is no longer used.
* `picom` now tries to give itself a real-time scheduling priority. ~~Please consider giving `picom` the `CAP_SYS_NICE` capability when packaging it.~~

## Deprecations

* The `kawase` blur method is removed. Note this is just an alias to the `dual_kawase` method, which is still available. (#1102)

# Earlier versions

Please see the GitHub releases page.
23 changes: 12 additions & 11 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@
overlays = [ overlay ];
in rec {
inherit overlay overlays;
defaultPackage = pkgs.picom;
defaultPackage = pkgs.picom.overrideAttrs {
version = "11";
src = ./.;
};
devShell = defaultPackage.overrideAttrs {
buildInputs = defaultPackage.buildInputs ++ [
pkgs.clang-tools
pkgs.clang-tools_17
pkgs.llvmPackages_17.clang-unwrapped.python
];
hardeningDisable = [ "fortify" ];
};
});
}
3 changes: 0 additions & 3 deletions man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ OPTIONS
*-f*, *--fading*::
Fade windows in/out when opening/closing and when opacity changes, unless *--no-fading-openclose* is used.

*-F*::
Equals to *-f*. Deprecated.

*-i*, *--inactive-opacity*='OPACITY'::
Opacity of inactive windows. (0.1 - 1.0, defaults to 1.0)

Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project('picom', 'c', version: '10',
project('picom', 'c', version: '11',
default_options: ['c_std=c11', 'warning_level=1'])

cc = meson.get_compiler('c')
Expand Down
22 changes: 13 additions & 9 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,17 @@ void handle_device_reset(session_t *ps) {
}

/// paint all windows
void paint_all_new(session_t *ps, struct managed_win *t) {
///
/// Returns if any render command is issued. IOW if nothing on the screen has changed,
/// this function will return false.
bool paint_all_new(session_t *ps, struct managed_win *const t) {
struct timespec now = get_time_timespec();
auto paint_all_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) {
return handle_device_reset(ps);
handle_device_reset(ps);
return false;
}
if (ps->o.xrender_sync_fence) {
if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) {
Expand All @@ -166,7 +170,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {

if (!pixman_region32_not_empty(&reg_damage)) {
pixman_region32_fini(&reg_damage);
return;
return false;
}

#ifdef DEBUG_REPAINT
Expand Down Expand Up @@ -242,16 +246,15 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
auto after_damage_us = (uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
log_trace("Getting damage took %" PRIu64 " us", after_damage_us - after_sync_fence_us);
if (ps->next_render > 0) {
log_trace("Render schedule deviation: %ld us (%s) %" PRIu64 " %ld",
labs((long)after_damage_us - (long)ps->next_render),
after_damage_us < ps->next_render ? "early" : "late",
after_damage_us, ps->next_render);
log_verbose("Render schedule deviation: %ld us (%s) %" PRIu64 " %ld",
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;
}
}
ps->did_render = true;

if (ps->backend_data->ops->prepare) {
ps->backend_data->ops->prepare(ps->backend_data, &reg_paint);
Expand All @@ -271,7 +274,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
// on top of that window. This is used to reduce the number of pixels painted.
//
// Whether this is beneficial is to be determined XXX
for (auto w = t; w; w = w->prev_trans) {
for (struct managed_win *w = t; w; w = w->prev_trans) {
pixman_region32_subtract(&reg_visible, &ps->screen_reg, w->reg_ignore);
assert(!(w->flags & WIN_FLAGS_IMAGE_ERROR));
assert(!(w->flags & WIN_FLAGS_PIXMAP_STALE));
Expand Down Expand Up @@ -595,6 +598,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
for (win *w = t; w; w = w->prev_trans)
log_trace(" %#010lx", w->id);
#endif
return true;
}

// vim: set noet sw=8 ts=8 :
6 changes: 5 additions & 1 deletion src/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,8 @@ struct backend_operations {

extern struct backend_operations *backend_list[];

void paint_all_new(session_t *ps, struct managed_win *const t) attr_nonnull(1);
/// paint all windows
///
/// Returns if any render command is issued. IOW if nothing on the screen has changed,
/// this function will return false.
bool paint_all_new(session_t *ps, struct managed_win *t) attr_nonnull(1);
7 changes: 7 additions & 0 deletions src/backend/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ void apply_driver_workarounds(struct session *ps, enum driver driver) {
}
}

enum vblank_scheduler_type choose_vblank_scheduler(enum driver driver) {
if (driver & DRIVER_NVIDIA) {
return VBLANK_SCHEDULER_SGI_VIDEO_SYNC;
}
return VBLANK_SCHEDULER_PRESENT;
}

enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_window_t window) {
enum driver ret = 0;
// First we try doing backend agnostic detection using RANDR
Expand Down
3 changes: 3 additions & 0 deletions src/backend/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdio.h>
#include <xcb/xcb.h>

#include "config.h"
#include "utils.h"

struct session;
Expand Down Expand Up @@ -41,6 +42,8 @@ enum driver detect_driver(xcb_connection_t *, struct backend_base *, xcb_window_

/// Apply driver specified global workarounds. It's safe to call this multiple times.
void apply_driver_workarounds(struct session *ps, enum driver);
/// Choose a vblank scheduler based on the driver.
enum vblank_scheduler_type choose_vblank_scheduler(enum driver driver);

// Print driver names to stdout, for diagnostics
static inline void print_drivers(enum driver drivers) {
Expand Down
27 changes: 14 additions & 13 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ typedef struct session {
// === Event handlers ===
/// ev_io for X connection
ev_io xiow;
/// Timer for checking DPMS power level
ev_timer dpms_check_timer;
/// Timeout for delayed unredirection.
ev_timer unredir_timer;
/// Timer for fading
Expand Down Expand Up @@ -218,26 +216,19 @@ typedef struct session {
bool first_frame;
/// Whether screen has been turned off
bool screen_is_off;
/// Event context for X Present extension.
uint32_t present_event_id;
xcb_special_event_t *present_event;
/// When last MSC event happened, in useconds.
uint64_t last_msc_instant;
/// The last MSC number
uint64_t last_msc;
/// When the currently rendered frame will be displayed.
/// 0 means there is no pending frame.
uint64_t target_msc;
/// The delay between when the last frame was scheduled to be rendered, and when
/// the render actually started.
uint64_t last_schedule_delay;
/// When do we want our next frame to start rendering.
uint64_t next_render;
/// Did we actually render the last frame. Sometimes redraw will be scheduled only
/// to find out nothing has changed. In which case this will be set to false.
bool did_render;
/// Whether we can perform frame pacing.
bool frame_pacing;
/// Vblank event scheduler
struct vblank_scheduler *vblank_scheduler;

/// Render statistics
struct render_statistics render_stats;
Expand All @@ -249,8 +240,18 @@ typedef struct session {
options_t o;
/// Whether we have hit unredirection timeout.
bool tmout_unredir_hit;
/// Whether we need to redraw the screen
bool redraw_needed;
/// If the backend is busy. This means two things:
/// Either the backend is currently rendering a frame, or a frame has been
/// rendered but has yet to be presented. In either case, we should not start
/// another render right now. As if we start issuing rendering commands now, we
/// will have to wait for either the the current render to finish, or the current
/// back buffer to be become available again. In either case, we will be wasting
/// time.
bool backend_busy;
/// Whether a render is queued. This generally means there are pending updates
/// to the screen that's neither included in the current render, nor on the
/// screen.
bool render_queued;

/// Cache a xfixes region so we don't need to allocate it every time.
/// A workaround for yshui/picom#301
Expand Down
79 changes: 79 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -617,6 +619,82 @@ char *locate_auxiliary_file(const char *scope, const char *path, const char *inc
return NULL;
}

struct debug_options_entry {
const char *name;
const char **choices;
size_t offset;
};

// clang-format off
const char *vblank_scheduler_str[] = {
[VBLANK_SCHEDULER_PRESENT] = "present",
[VBLANK_SCHEDULER_SGI_VIDEO_SYNC] = "sgi_video_sync",
[LAST_VBLANK_SCHEDULER] = NULL
};
static const struct debug_options_entry debug_options_entries[] = {
{"smart_frame_pacing", NULL, offsetof(struct debug_options, smart_frame_pacing)},
{"force_vblank_sched", vblank_scheduler_str, offsetof(struct debug_options, force_vblank_scheduler)},
};
// clang-format on

void parse_debug_option_single(char *setting, struct debug_options *debug_options) {
char *equal = strchr(setting, '=');
size_t name_len = equal ? (size_t)(equal - setting) : strlen(setting);
for (size_t i = 0; i < ARR_SIZE(debug_options_entries); i++) {
if (strncmp(setting, debug_options_entries[i].name, name_len) != 0) {
continue;
}
if (debug_options_entries[i].name[name_len] != '\0') {
continue;
}
auto value = (int *)((void *)debug_options + debug_options_entries[i].offset);
if (equal) {
const char *const arg = equal + 1;
if (debug_options_entries[i].choices != NULL) {
for (size_t j = 0; debug_options_entries[i].choices[j]; j++) {
if (strcmp(arg, debug_options_entries[i].choices[j]) ==
0) {
*value = (int)j;
return;
}
}
}
if (!parse_int(arg, value)) {
log_error("Invalid value for debug option %s: %s, it "
"will be ignored.",
debug_options_entries[i].name, arg);
}
} else if (debug_options_entries[i].choices == NULL) {
*value = 1;
} else {
log_error(
"Missing value for debug option %s, it will be ignored.", setting);
}
return;
}
log_error("Invalid debug option: %s", setting);
}

/// Parse debug options from environment variable `PICOM_DEBUG`.
void parse_debug_options(struct debug_options *debug_options) {
const char *debug = getenv("PICOM_DEBUG");
const struct debug_options default_debug_options = {
.force_vblank_scheduler = LAST_VBLANK_SCHEDULER,
};

*debug_options = default_debug_options;
if (!debug) {
return;
}

scoped_charp debug_copy = strdup(debug);
char *tmp, *needle = strtok_r(debug_copy, ";", &tmp);
while (needle) {
parse_debug_option_single(needle, debug_options);
needle = strtok_r(NULL, ";", &tmp);
}
}

/**
* Parse a list of window shader rules.
*/
Expand Down Expand Up @@ -870,5 +948,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
(void)hasneg;
(void)winopt_mask;
#endif
parse_debug_options(&opt->debug_options);
return ret;
}
Loading

0 comments on commit 2417084

Please sign in to comment.