Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2 frames 2 pacing #1156

Merged
merged 18 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,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 @@ -114,7 +118,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 @@ -199,7 +203,6 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
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 @@ -219,7 +222,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 @@ -541,6 +544,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 @@ -366,4 +366,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);
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 @@ -214,26 +212,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 @@ -245,8 +236,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
68 changes: 68 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -615,6 +616,72 @@ char *locate_auxiliary_file(const char *scope, const char *path, const char *inc
return ret;
}

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

static const struct debug_options_entry debug_options_entries[] = {

};

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 = {};

*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 @@ -817,5 +884,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;
}
17 changes: 17 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ enum blur_method {

typedef struct _c2_lptr c2_lptr_t;

enum vblank_scheduler_type {
/// X Present extension based vblank events
VBLANK_SCHEDULER_PRESENT,
/// GLX_SGI_video_sync based vblank events
VBLANK_SCHEDULER_SGI_VIDEO_SYNC,
/// An invalid scheduler, served as a scheduler count, and
/// as a sentinel value.
LAST_VBLANK_SCHEDULER,
};

/// Internal, private options for debugging and development use.
struct debug_options {

};

/// Structure representing all options.
typedef struct options {
// === Debugging ===
Expand Down Expand Up @@ -262,6 +277,8 @@ typedef struct options {
c2_lptr_t *transparent_clipping_blacklist;

bool dithered_present;

struct debug_options debug_options;
} options_t;

extern const char *const BACKEND_STRS[NUM_BKEND + 1];
Expand Down
3 changes: 2 additions & 1 deletion src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,8 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
// XXX redraw needs to be more fine grained
queue_redraw(ps);

// the events sent from SendEvent will be ignored
// We intentionally ignore events sent via SendEvent. Those events has the 8th bit
// of response_type set, meaning they will match none of the cases below.
switch (ev->response_type) {
case FocusIn: ev_focus_in(ps, (xcb_focus_in_event_t *)ev); break;
case FocusOut: ev_focus_out(ps, (xcb_focus_out_event_t *)ev); break;
Expand Down
3 changes: 2 additions & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ base_deps = [

srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c',
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c',
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c') ]
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c',
'vblank.c') ]
picom_inc = include_directories('.')

cflags = []
Expand Down
Loading