summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlija Hadzic <ilijahadzic@gmail.com>2013-05-08 22:39:42 -0400
committerMichel Dänzer <michel@daenzer.net>2013-05-29 15:17:00 +0200
commitffaa5abf207415159cdb28e90da49b95f497ef61 (patch)
tree500791b3c9ee5fe9d2c6b4e4cd6edc0c67fa8b19
parent80ae2291d082b57c70d27a80182f00d760fb3d3a (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.c76
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.
*/