[PATCH 05/11] drmmode: calculate interpolated vblanks while in dpms-off state

Ilija Hadzic ilijahadzic at gmail.com
Sun Apr 28 13:07:50 PDT 2013


This adds provisions for interpolating vblanks while the CRTC
is in DPMS-off state. When entering DPMS-off state, we
record the last vblank time, sequence number and period
in CRTC-private structure.

When going back to DPMS-on state we read the current
time and calculate how long we have been off. Then we derive
how many vblanks that would have been had the CRTC remained
running. These are the interpolated vblanks.

Finally, we accumulate the number of interpolated vblanks
in CRTC-private structure to get the number of interpolated
vblanks over the system lifetime.

Signed-off-by: Ilija Hadzic <ihadzic at research.bell-labs.com>
---
 src/drmmode_display.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/drmmode_display.h |  4 ++++
 2 files changed, 57 insertions(+)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 7bc3eeb..e279728 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -49,6 +49,8 @@
 #include <X11/extensions/dpms.h>
 #endif
 
+#define DEFAULT_NOMINAL_VBLANK_PERIOD 16667
+
 static Bool
 RADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
 {
@@ -245,7 +247,58 @@ static void
 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
 {
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	ScrnInfoPtr scrn = crtc->scrn;
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	CARD64 ust;
+	int ret;
+
+	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
+		drmVBlank vbl;
 
+		/*
+		 * On->Off transition: record the last vblank time,
+		 * sequence number and frame period.
+		 */
+		vbl.request.type = DRM_VBLANK_RELATIVE;
+		vbl.request.type |= radeon_populate_vbl_request_type(crtc);
+		vbl.request.sequence = 0;
+		ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
+		if (ret)
+			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+				   "%s cannot get last vblank counter\n",
+				   __func__);
+		else {
+			CARD64 seq = (CARD64)vbl.reply.sequence;
+			uint64_t nominal_vblank_period;
+
+			ust = ((CARD64)vbl.reply.tval_sec * 1000000) +
+				vbl.reply.tval_usec;
+			drmmode_crtc->dpms_last_ust = ust;
+			drmmode_crtc->dpms_last_seq = seq;
+			nominal_vblank_period = crtc->mode.HTotal * crtc->mode.VTotal;
+			nominal_vblank_period *= 1000;
+			if (nominal_vblank_period == 0 ||  crtc->mode.Clock == 0)
+				nominal_vblank_period = DEFAULT_NOMINAL_VBLANK_PERIOD;
+			else
+				nominal_vblank_period /= crtc->mode.Clock;
+			drmmode_crtc->dpms_last_nvp = nominal_vblank_period;
+		}
+	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
+		/*
+		 * Off->On transition: calculate and accumulate the
+		 * number of interpolated vblanks while we were in Off state
+		 */
+		ret = drmmode_get_current_ust(info->dri2.drm_fd, &ust);
+		if (ret)
+			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+				   "%s cannot get current time\n", __func__);
+		else if (drmmode_crtc->dpms_last_ust) {
+			CARD64 time_elapsed;
+			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
+			drmmode_crtc->interpolated_vblanks +=
+				time_elapsed / drmmode_crtc->dpms_last_nvp;
+		}
+	}
 	drmmode_crtc->dpms_mode = mode;
 }
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 2e56893..5dcb9bf 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -72,6 +72,10 @@ typedef struct {
     struct radeon_bo *rotate_bo;
     unsigned rotate_fb_id;
     int dpms_mode;
+    CARD64 dpms_last_ust;
+    uint32_t dpms_last_seq;
+    int dpms_last_nvp;
+    uint32_t interpolated_vblanks;
     uint16_t lut_r[256], lut_g[256], lut_b[256];
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
-- 
1.8.1.5



More information about the xorg-driver-ati mailing list