mirror of https://github.com/yshui/picom.git
vblank: reset SGI_video_sync scheduler if it's getting nonsense
If resetting fails, set a flag so all future schedule calls will fail. Fixes #1168 Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
0638de5c56
commit
238c3cc833
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
* Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170)
|
* Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170)
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
|
||||||
|
* Workaround a NVIDIA problem that causes high CPU usage after suspend/resume (#1172, #1168)
|
||||||
|
|
||||||
# v11.1 (2024-Jan-28)
|
# v11.1 (2024-Jan-28)
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
|
|
58
src/vblank.c
58
src/vblank.c
|
@ -77,13 +77,14 @@ struct sgi_video_sync_vblank_scheduler {
|
||||||
|
|
||||||
// Since glXWaitVideoSyncSGI blocks, we need to run it in a separate thread.
|
// Since glXWaitVideoSyncSGI blocks, we need to run it in a separate thread.
|
||||||
// ... and all the thread shenanigans that come with it.
|
// ... and all the thread shenanigans that come with it.
|
||||||
_Atomic unsigned int last_msc;
|
_Atomic unsigned int current_msc;
|
||||||
_Atomic uint64_t last_ust;
|
_Atomic uint64_t current_ust;
|
||||||
ev_async notify;
|
ev_async notify;
|
||||||
pthread_t sync_thread;
|
pthread_t sync_thread;
|
||||||
bool running, error;
|
bool running, error;
|
||||||
|
unsigned int last_msc;
|
||||||
|
|
||||||
/// Protects `running`, `error` and `base.vblank_event_requested`
|
/// Protects `running`, and `base.vblank_event_requested`
|
||||||
pthread_mutex_t vblank_requested_mtx;
|
pthread_mutex_t vblank_requested_mtx;
|
||||||
pthread_cond_t vblank_requested_cnd;
|
pthread_cond_t vblank_requested_cnd;
|
||||||
};
|
};
|
||||||
|
@ -208,8 +209,8 @@ static void *sgi_video_sync_thread(void *data) {
|
||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
atomic_store(&self->last_msc, last_msc);
|
atomic_store(&self->current_msc, last_msc);
|
||||||
atomic_store(&self->last_ust,
|
atomic_store(&self->current_ust,
|
||||||
(uint64_t)(now.tv_sec * 1000000 + now.tv_nsec / 1000));
|
(uint64_t)(now.tv_sec * 1000000 + now.tv_nsec / 1000));
|
||||||
ev_async_send(self->base.loop, &self->notify);
|
ev_async_send(self->base.loop, &self->notify);
|
||||||
pthread_mutex_lock(&self->vblank_requested_mtx);
|
pthread_mutex_lock(&self->vblank_requested_mtx);
|
||||||
|
@ -242,7 +243,10 @@ cleanup:
|
||||||
|
|
||||||
static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) {
|
static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) {
|
||||||
auto self = (struct sgi_video_sync_vblank_scheduler *)base;
|
auto self = (struct sgi_video_sync_vblank_scheduler *)base;
|
||||||
log_verbose("Requesting vblank event for msc %d", self->last_msc + 1);
|
if (self->error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
log_verbose("Requesting vblank event for msc %d", self->current_msc + 1);
|
||||||
pthread_mutex_lock(&self->vblank_requested_mtx);
|
pthread_mutex_lock(&self->vblank_requested_mtx);
|
||||||
assert(!base->vblank_event_requested);
|
assert(!base->vblank_event_requested);
|
||||||
base->vblank_event_requested = true;
|
base->vblank_event_requested = true;
|
||||||
|
@ -252,16 +256,7 @@ static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents) {
|
sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents);
|
||||||
auto sched = container_of(w, struct sgi_video_sync_vblank_scheduler, notify);
|
|
||||||
auto event = (struct vblank_event){
|
|
||||||
.msc = atomic_load(&sched->last_msc),
|
|
||||||
.ust = atomic_load(&sched->last_ust),
|
|
||||||
};
|
|
||||||
sched->base.vblank_event_requested = false;
|
|
||||||
log_verbose("Received vblank event for msc %lu", event.msc);
|
|
||||||
vblank_scheduler_invoke_callbacks(&sched->base, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) {
|
static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) {
|
||||||
auto self = (struct sgi_video_sync_vblank_scheduler *)base;
|
auto self = (struct sgi_video_sync_vblank_scheduler *)base;
|
||||||
|
@ -293,6 +288,8 @@ static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) {
|
||||||
} else {
|
} else {
|
||||||
log_info("Started sgi_video_sync_thread");
|
log_info("Started sgi_video_sync_thread");
|
||||||
}
|
}
|
||||||
|
self->error = !succeeded;
|
||||||
|
self->last_msc = 0;
|
||||||
pthread_mutex_destroy(&args.start_mtx);
|
pthread_mutex_destroy(&args.start_mtx);
|
||||||
pthread_cond_destroy(&args.start_cnd);
|
pthread_cond_destroy(&args.start_cnd);
|
||||||
return succeeded;
|
return succeeded;
|
||||||
|
@ -311,6 +308,35 @@ static void sgi_video_sync_scheduler_deinit(struct vblank_scheduler *base) {
|
||||||
pthread_mutex_destroy(&self->vblank_requested_mtx);
|
pthread_mutex_destroy(&self->vblank_requested_mtx);
|
||||||
pthread_cond_destroy(&self->vblank_requested_cnd);
|
pthread_cond_destroy(&self->vblank_requested_cnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents) {
|
||||||
|
auto sched = container_of(w, struct sgi_video_sync_vblank_scheduler, notify);
|
||||||
|
auto msc = atomic_load(&sched->current_msc);
|
||||||
|
if (sched->last_msc == msc) {
|
||||||
|
// NVIDIA spams us with duplicate vblank events after a suspend/resume
|
||||||
|
// cycle. Recreating the X connection and GLX context seems to fix this.
|
||||||
|
// Oh NVIDIA.
|
||||||
|
log_warn("Duplicate vblank event found with msc %d. Possible NVIDIA bug?", msc);
|
||||||
|
log_warn("Resetting the vblank scheduler");
|
||||||
|
sgi_video_sync_scheduler_deinit(&sched->base);
|
||||||
|
sched->base.vblank_event_requested = false;
|
||||||
|
if (!sgi_video_sync_scheduler_init(&sched->base)) {
|
||||||
|
log_error("Failed to reset the vblank scheduler");
|
||||||
|
} else {
|
||||||
|
sgi_video_sync_scheduler_schedule(&sched->base);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto event = (struct vblank_event){
|
||||||
|
.msc = msc,
|
||||||
|
.ust = atomic_load(&sched->current_ust),
|
||||||
|
};
|
||||||
|
sched->base.vblank_event_requested = false;
|
||||||
|
sched->last_msc = msc;
|
||||||
|
log_verbose("Received vblank event for msc %lu", event.msc);
|
||||||
|
vblank_scheduler_invoke_callbacks(&sched->base, &event);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool present_vblank_scheduler_schedule(struct vblank_scheduler *base) {
|
static bool present_vblank_scheduler_schedule(struct vblank_scheduler *base) {
|
||||||
|
|
Loading…
Reference in New Issue