Skip to content

Commit 66d253e

Browse files
authored
Merge branch 'yshui:next' into next
2 parents 3c5ce3c + 01b6766 commit 66d253e

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

src/vblank.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ struct sgi_video_sync_vblank_scheduler {
8787
pthread_t sync_thread;
8888
bool running, error, vblank_requested;
8989
unsigned int last_msc;
90+
/// Number of synthesized vblank event. Currently these are being inserted when
91+
/// the driver reports duplicate msc to us.
92+
///
93+
/// This is because the NVIDIA driver has been observed to recover from a
94+
/// duplicated msc loop by us rendering a new frame. So we insert a fake vblank
95+
/// event so the render loop can progress, but doing so makes our msc desync from
96+
/// the driver's msc. An hypothetical sequence of events go like this:
97+
///
98+
/// - driver -> msc 1, we report msc 1
99+
/// - driver -> msc 1 (duplicate msc! if we don't render a new frame, we'll
100+
/// be stuck here forever)
101+
/// - we report msc 2
102+
/// - new frame rendered, driver recover
103+
/// - driver -> msc 2, but we already reported msc 2, so we have to report msc 3
104+
unsigned int vblank_inserted;
90105

91106
/// Protects `running`, and `vblank_requested`
92107
pthread_mutex_t vblank_requested_mtx;
@@ -199,6 +214,8 @@ static void *sgi_video_sync_thread(void *data) {
199214
pthread_cond_signal(&args->start_cnd);
200215
pthread_mutex_unlock(&args->start_mtx);
201216

217+
unsigned int last_msc = 0;
218+
202219
pthread_mutex_lock(&self->vblank_requested_mtx);
203220
while (self->running) {
204221
if (!self->vblank_requested) {
@@ -208,10 +225,9 @@ static void *sgi_video_sync_thread(void *data) {
208225
}
209226
pthread_mutex_unlock(&self->vblank_requested_mtx);
210227

211-
unsigned int last_msc;
212228
glXWaitVideoSyncSGI(1, 0, &last_msc);
213229

214-
struct timespec now;
230+
struct timespec now = {};
215231
clock_gettime(CLOCK_MONOTONIC, &now);
216232
atomic_store(&self->current_msc, last_msc);
217233
atomic_store(&self->current_ust,
@@ -323,28 +339,33 @@ static void sgi_video_sync_scheduler_deinit(struct vblank_scheduler *base) {
323339
static void
324340
sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents) {
325341
auto sched = container_of(w, struct sgi_video_sync_vblank_scheduler, notify);
326-
auto msc = atomic_load(&sched->current_msc);
327-
if (sched->last_msc == msc) {
342+
auto msc = atomic_load(&sched->current_msc) + sched->vblank_inserted;
343+
auto ust = atomic_load(&sched->current_ust);
344+
if (sched->last_msc >= msc) {
328345
// NVIDIA spams us with duplicate vblank events after a suspend/resume
329-
// cycle. Recreating the X connection and GLX context seems to fix this.
330-
// Oh NVIDIA.
331-
log_warn("Duplicate vblank event found with msc %d. Possible NVIDIA bug?", msc);
332-
log_warn("Resetting the vblank scheduler");
333-
sgi_video_sync_scheduler_deinit(&sched->base);
334-
sched->base.vblank_event_requested = false;
335-
if (!sgi_video_sync_scheduler_init(&sched->base)) {
336-
log_error("Failed to reset the vblank scheduler");
337-
} else {
338-
sgi_video_sync_scheduler_schedule(&sched->base);
339-
}
340-
return;
346+
// cycle, or when the monitor turns off.
347+
// Fake a vblank event in this case. See comments on `vblank_inserted`
348+
// for more details.
349+
enum log_level level =
350+
sched->vblank_inserted == 0 ? LOG_LEVEL_WARN : LOG_LEVEL_DEBUG;
351+
LOG_(level,
352+
"Duplicate vblank event found with msc %d. Possible NVIDIA bug? "
353+
"Number of duplicates so far: %d",
354+
msc, sched->vblank_inserted);
355+
sched->last_msc++;
356+
sched->vblank_inserted++;
357+
358+
struct timespec now;
359+
clock_gettime(CLOCK_MONOTONIC, &now);
360+
ust = (uint64_t)(now.tv_sec * 1000000 + now.tv_nsec / 1000);
361+
} else {
362+
sched->last_msc = msc;
341363
}
342364
auto event = (struct vblank_event){
343-
.msc = msc,
344-
.ust = atomic_load(&sched->current_ust),
365+
.msc = sched->last_msc,
366+
.ust = ust,
345367
};
346368
sched->base.vblank_event_requested = false;
347-
sched->last_msc = msc;
348369
log_verbose("Received vblank event for msc %" PRIu64, event.msc);
349370
vblank_scheduler_invoke_callbacks(&sched->base, &event);
350371
}

0 commit comments

Comments
 (0)