mirror of
https://github.com/yshui/picom.git
synced 2024-11-11 13:51:02 -05:00
core: always check if render is finished at next vblank
Right now we rely on `reschedule_render_at_vblank` being scheduled for the render finish check. Which means we will only know if a frame has finished rendering the next time we queue a render. And we only check at vblank boundary, which means when a render is queued we have to wait for the next vblank, when had we checked earlier, we will be able to start rendering immediately Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
c42e6cef0a
commit
dd83f550e1
1 changed files with 40 additions and 24 deletions
64
src/picom.c
64
src/picom.c
|
@ -145,6 +145,38 @@ static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum vblank_callback_action check_render_finish(struct vblank_event *e attr_unused, void *ud) {
|
||||||
|
auto ps = (session_t *)ud;
|
||||||
|
if (!ps->backend_busy) {
|
||||||
|
return VBLANK_CALLBACK_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec render_time;
|
||||||
|
bool completed =
|
||||||
|
ps->backend_data->ops->last_render_time(ps->backend_data, &render_time);
|
||||||
|
if (!completed) {
|
||||||
|
// Render hasn't completed yet, we can't start another render.
|
||||||
|
// Check again at the next vblank.
|
||||||
|
log_debug("Last render did not complete during vblank, msc: "
|
||||||
|
"%" PRIu64,
|
||||||
|
ps->last_msc);
|
||||||
|
return VBLANK_CALLBACK_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The frame has been finished and presented, record its render time.
|
||||||
|
if (ps->o.debug_options.smart_frame_pacing) {
|
||||||
|
int render_time_us =
|
||||||
|
(int)(render_time.tv_sec * 1000000L + render_time.tv_nsec / 1000L);
|
||||||
|
render_statistics_add_render_time_sample(
|
||||||
|
&ps->render_stats, render_time_us + (int)ps->last_schedule_delay);
|
||||||
|
log_verbose("Last render call took: %d (gpu) + %d (cpu) us, "
|
||||||
|
"last_msc: %" PRIu64,
|
||||||
|
render_time_us, (int)ps->last_schedule_delay, ps->last_msc);
|
||||||
|
}
|
||||||
|
ps->backend_busy = false;
|
||||||
|
return VBLANK_CALLBACK_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
enum vblank_callback_action
|
enum vblank_callback_action
|
||||||
collect_vblank_interval_statistics(struct vblank_event *e, void *ud) {
|
collect_vblank_interval_statistics(struct vblank_event *e, void *ud) {
|
||||||
auto ps = (session_t *)ud;
|
auto ps = (session_t *)ud;
|
||||||
|
@ -216,32 +248,10 @@ enum vblank_callback_action reschedule_render_at_vblank(struct vblank_event *e,
|
||||||
log_verbose("Rescheduling render at vblank, msc: %" PRIu64, e->msc);
|
log_verbose("Rescheduling render at vblank, msc: %" PRIu64, e->msc);
|
||||||
|
|
||||||
collect_vblank_interval_statistics(e, ud);
|
collect_vblank_interval_statistics(e, ud);
|
||||||
|
check_render_finish(e, ud);
|
||||||
|
|
||||||
if (ps->backend_busy) {
|
if (ps->backend_busy) {
|
||||||
struct timespec render_time;
|
return VBLANK_CALLBACK_AGAIN;
|
||||||
bool completed =
|
|
||||||
ps->backend_data->ops->last_render_time(ps->backend_data, &render_time);
|
|
||||||
if (!completed) {
|
|
||||||
// Render hasn't completed yet, we can't start another render.
|
|
||||||
// Check again at the next vblank.
|
|
||||||
log_debug("Last render did not complete during vblank, msc: "
|
|
||||||
"%" PRIu64,
|
|
||||||
ps->last_msc);
|
|
||||||
return VBLANK_CALLBACK_AGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The frame has been finished and presented, record its render time.
|
|
||||||
if (ps->o.debug_options.smart_frame_pacing) {
|
|
||||||
int render_time_us = (int)(render_time.tv_sec * 1000000L +
|
|
||||||
render_time.tv_nsec / 1000L);
|
|
||||||
render_statistics_add_render_time_sample(
|
|
||||||
&ps->render_stats, render_time_us + (int)ps->last_schedule_delay);
|
|
||||||
log_verbose("Last render call took: %d (gpu) + %d (cpu) us, "
|
|
||||||
"last_msc: %" PRIu64,
|
|
||||||
render_time_us, (int)ps->last_schedule_delay,
|
|
||||||
ps->last_msc);
|
|
||||||
}
|
|
||||||
ps->backend_busy = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule_render(ps, false);
|
schedule_render(ps, false);
|
||||||
|
@ -1815,6 +1825,12 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
|
||||||
if (animation) {
|
if (animation) {
|
||||||
queue_redraw(ps);
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
|
if (ps->vblank_scheduler) {
|
||||||
|
// Even if we might not want to render during next vblank, we want to keep
|
||||||
|
// `backend_busy` up to date, so when the next render comes, we can
|
||||||
|
// immediately know if we can render.
|
||||||
|
vblank_scheduler_schedule(ps->vblank_scheduler, check_render_finish, ps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_callback(EV_P_ ev_timer *w, int revents) {
|
static void draw_callback(EV_P_ ev_timer *w, int revents) {
|
||||||
|
|
Loading…
Reference in a new issue