mirror of
https://github.com/yshui/picom.git
synced 2024-11-11 13:51:02 -05:00
vblank: winding down vblank events instead of stopping immediately
I noticed sometimes full frame rate video is rendered at half frame rate sometimes. That is because the damage notify is sent very close to vblank, and since we request vblank events when we get the damage, we miss the vblank event immediately after, despite the damage happening before the vblank. request next ...... next next damage vblank vblank vblank | | | ...... | v v v v ---------------------->>>>>>--------- `request vblank` is triggered by `damage`, but because it's too close to `next vblank`, that vblank is missed despite we requested before it happening, and we only get `next next vblank`. The result is we will drop every other frame. The solution in this commit is that we will keep requesting vblank events, right after we received a vblank event, even when nobody is asking for them. We would do that for a set number of vblanks before stopping (currently 4). Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
25d16b0352
commit
c42e6cef0a
1 changed files with 15 additions and 2 deletions
17
src/vblank.c
17
src/vblank.c
|
@ -18,11 +18,19 @@ struct vblank_closure {
|
|||
void *user_data;
|
||||
};
|
||||
|
||||
#define VBLANK_WIND_DOWN 4
|
||||
|
||||
struct vblank_scheduler {
|
||||
struct x_connection *c;
|
||||
size_t callback_capacity, callback_count;
|
||||
struct vblank_closure *callbacks;
|
||||
struct ev_loop *loop;
|
||||
/// Request extra vblank events even when no callbacks are scheduled.
|
||||
/// This is because when callbacks are scheduled too close to a vblank,
|
||||
/// we might send PresentNotifyMsc request too late and miss the vblank event.
|
||||
/// So we request extra vblank events right after the last vblank event
|
||||
/// to make sure this doesn't happen.
|
||||
unsigned int wind_down;
|
||||
xcb_window_t target_window;
|
||||
enum vblank_scheduler_type type;
|
||||
bool vblank_event_requested;
|
||||
|
@ -178,7 +186,7 @@ static void vblank_scheduler_schedule_internal(struct vblank_scheduler *self) {
|
|||
|
||||
bool vblank_scheduler_schedule(struct vblank_scheduler *self,
|
||||
vblank_callback_t vblank_callback, void *user_data) {
|
||||
if (self->callback_count == 0) {
|
||||
if (self->callback_count == 0 && self->wind_down == 0) {
|
||||
vblank_scheduler_schedule_internal(self);
|
||||
}
|
||||
if (self->callback_count == self->callback_capacity) {
|
||||
|
@ -204,6 +212,11 @@ vblank_scheduler_invoke_callbacks(struct vblank_scheduler *self, struct vblank_e
|
|||
// callbacks might be added during callback invocation, so we need to
|
||||
// copy the callback_count.
|
||||
size_t count = self->callback_count, write_head = 0;
|
||||
if (count == 0) {
|
||||
self->wind_down--;
|
||||
} else {
|
||||
self->wind_down = VBLANK_WIND_DOWN;
|
||||
}
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto action = self->callbacks[i].fn(event, self->callbacks[i].user_data);
|
||||
switch (action) {
|
||||
|
@ -222,7 +235,7 @@ vblank_scheduler_invoke_callbacks(struct vblank_scheduler *self, struct vblank_e
|
|||
assert(count == self->callback_count && "callbacks should not be added when "
|
||||
"callbacks are being invoked.");
|
||||
self->callback_count = write_head;
|
||||
if (self->callback_count) {
|
||||
if (self->callback_count || self->wind_down) {
|
||||
vblank_scheduler_schedule_internal(self);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue