diff options
author | Ilija Hadzic <ilijahadzic@gmail.com> | 2013-05-08 22:39:42 -0400 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2013-05-29 15:17:00 +0200 |
commit | ffaa5abf207415159cdb28e90da49b95f497ef61 (patch) | |
tree | 500791b3c9ee5fe9d2c6b4e4cd6edc0c67fa8b19 | |
parent | 80ae2291d082b57c70d27a80182f00d760fb3d3a (diff) |
DRI2: add vblank extrapolation function
Implement a helper function that will be called when emulating
the running CRTC. The function should be called only when CRTC
is in DPMS-off state. It will look at the vblank count and the
time that was recorded last time the CRTC was running and
calculate how long one must wait (from present time) until
the target_msc is reached if the CRTC were running.
v2: - CRTC-private now stores frame rate instead of nominal
vblank period.
- DIX's timer facility can sometimes wake up the scheduled
functions more than a millisecond earlier. To avoid
generating an old MSC, we have to add more margin when
converting the delay in microseconds to milliseconds.
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | src/radeon_dri2.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index cd2be2bd..d113486a 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -875,6 +875,82 @@ drmVBlankSeqType radeon_populate_vbl_request_type(xf86CrtcPtr crtc) } /* + * This function should be called on a disabled CRTC only (i.e., CRTC + * in DPMS-off state). It will calculate the delay necessary to reach + * target_msc from present time if the CRTC were running. + */ +static +CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, + CARD64 divisor, CARD64 remainder) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + int nominal_frame_rate = drmmode_crtc->dpms_last_fps; + CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; + int last_vblank_seq = drmmode_crtc->dpms_last_seq; + int interpolated_vblanks = drmmode_crtc->interpolated_vblanks; + int target_seq; + CARD64 now, target_time, delta_t; + int64_t d, delta_seq; + int ret; + CARD32 d_ms; + + if (!last_vblank_ust) { + *target_msc = 0; + return FALLBACK_SWAP_DELAY; + } + ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); + if (ret) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "%s cannot get current time\n", __func__); + *target_msc = 0; + return FALLBACK_SWAP_DELAY; + } + target_seq = (int)*target_msc - interpolated_vblanks; + delta_seq = (int64_t)target_seq - (int64_t)last_vblank_seq; + delta_seq *= 1000000; + target_time = last_vblank_ust; + target_time += delta_seq / nominal_frame_rate; + d = target_time - now; + if (d < 0) { + /* we missed the event, adjust target_msc, do the divisor magic */ + CARD64 current_msc; + current_msc = last_vblank_seq + interpolated_vblanks; + delta_t = now - last_vblank_ust; + delta_seq = delta_t * nominal_frame_rate; + current_msc += delta_seq / 1000000; + current_msc &= 0xffffffff; + if (divisor == 0) { + *target_msc = current_msc; + d = 0; + } else { + *target_msc = current_msc - (current_msc % divisor) + remainder; + if ((current_msc % divisor) >= remainder) + *target_msc += divisor; + *target_msc &= 0xffffffff; + target_seq = (int)*target_msc - interpolated_vblanks; + delta_seq = (int64_t)target_seq - (int64_t)last_vblank_seq; + delta_seq *= 1000000; + target_time = last_vblank_ust; + target_time += delta_seq / nominal_frame_rate; + d = target_time - now; + } + } + /* + * convert delay to milliseconds and add margin to prevent the client + * from coming back early (due to timer granularity and rounding + * errors) and getting the same MSC it just got + */ + d_ms = (CARD32)d / 1000; + if ((CARD32)d - d_ms * 1000 > 0) + d_ms += 2; + else + d_ms++; + return d_ms; +} + +/* * Get current frame count and frame count timestamp, based on drawable's * crtc. */ |