summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIlija Hadzic <ilijahadzic@gmail.com>2013-05-08 22:39:40 -0400
committerMichel Dänzer <michel@daenzer.net>2013-05-29 15:09:13 +0200
commit5fd2eb5d12cea32927a9e6c6ce4afd18aa7d046a (patch)
tree14fe7c18e24b44a589cadf03577422e80f278b7d /src
parente41ad30d09be4962cfb1942b0b9f63875dbb2d2a (diff)
drmmode: calculate interpolated vblanks while in dpms-off state
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 frame rate 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. v2: Track frame rate instead of vblank period. The former eliminates some roundoff errors. Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src')
-rw-r--r--src/drmmode_display.c56
-rw-r--r--src/drmmode_display.h4
2 files changed, 60 insertions, 0 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 658747c6..cd276f35 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -49,6 +49,8 @@
#include <X11/extensions/dpms.h>
#endif
+#define DEFAULT_NOMINAL_FRAME_RATE 60
+
static Bool
RADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
{
@@ -245,7 +247,61 @@ 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;
+ CARD64 nominal_frame_rate, pix_in_frame;
+
+ ust = ((CARD64)vbl.reply.tval_sec * 1000000) +
+ vbl.reply.tval_usec;
+ drmmode_crtc->dpms_last_ust = ust;
+ drmmode_crtc->dpms_last_seq = seq;
+ nominal_frame_rate = crtc->mode.Clock;
+ nominal_frame_rate *= 1000;
+ pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
+ if (nominal_frame_rate == 0 || pix_in_frame == 0)
+ nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
+ else
+ nominal_frame_rate /= pix_in_frame;
+ drmmode_crtc->dpms_last_fps = nominal_frame_rate;
+ }
+ } 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, delta_seq;
+ time_elapsed = ust - drmmode_crtc->dpms_last_ust;
+ delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
+ delta_seq /= 1000000;
+ drmmode_crtc->interpolated_vblanks += delta_seq;
+ }
+ }
drmmode_crtc->dpms_mode = mode;
}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index add2ee48..2fccfda7 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -76,6 +76,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_fps;
+ uint32_t interpolated_vblanks;
uint16_t lut_r[256], lut_g[256], lut_b[256];
} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;