Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bb403bf authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter
Browse files

drm: Stop using linedur_ns and pixeldur_ns for vblank timestamps



linedur_ns, and especially pixeldur_ns are becoming rather inaccurate
to be used for the vblank timestamp correction. With 4k@60 the pixel
duration is already below 2ns, so the amount of error due to the
truncation to nanoseconds is introducing quite a bit of error.

We can avoid such problems if we instead calculate the timestamp
delta_ns directly from the dislay timings, avoiding the use of
these intermediate truncated values.

Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
[danvet: Squash in fixup from Thierry Reding for amdgpu.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent eba1f35d
Loading
Loading
Loading
Loading
+6 −5
Original line number Original line Diff line number Diff line
@@ -745,7 +745,8 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
 *
 *
 */
 */
int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
			       int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
			       int *vpos, int *hpos, ktime_t *stime, ktime_t *etime,
			       const struct drm_display_mode *mode)
{
{
	u32 vbl = 0, position = 0;
	u32 vbl = 0, position = 0;
	int vbl_start, vbl_end, vtotal, ret = 0;
	int vbl_start, vbl_end, vtotal, ret = 0;
@@ -781,7 +782,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl
	}
	}
	else {
	else {
		/* No: Fake something reasonable which gives at least ok results. */
		/* No: Fake something reasonable which gives at least ok results. */
		vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
		vbl_start = mode->crtc_vdisplay;
		vbl_end = 0;
		vbl_end = 0;
	}
	}


@@ -797,7 +798,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl


	/* Inside "upper part" of vblank area? Apply corrective offset if so: */
	/* Inside "upper part" of vblank area? Apply corrective offset if so: */
	if (in_vbl && (*vpos >= vbl_start)) {
	if (in_vbl && (*vpos >= vbl_start)) {
		vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
		vtotal = mode->crtc_vtotal;
		*vpos = *vpos - vtotal;
		*vpos = *vpos - vtotal;
	}
	}


@@ -819,8 +820,8 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl
	 * We only do this if DRM_CALLED_FROM_VBLIRQ.
	 * We only do this if DRM_CALLED_FROM_VBLIRQ.
	 */
	 */
	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
		vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
		vbl_start = mode->crtc_vdisplay;
		vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
		vtotal = mode->crtc_vtotal;


		if (vbl_start - *vpos < vtotal / 100) {
		if (vbl_start - *vpos < vtotal / 100) {
			*vpos -= vtotal;
			*vpos -= vtotal;
+2 −1
Original line number Original line Diff line number Diff line
@@ -543,7 +543,8 @@ void amdgpu_encoder_set_active_device(struct drm_encoder *encoder);
int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
				      unsigned int flags,
				      unsigned int flags,
				      int *vpos, int *hpos, ktime_t *stime,
				      int *vpos, int *hpos, ktime_t *stime,
				      ktime_t *etime);
				      ktime_t *etime,
				      const struct drm_display_mode *mode);


int amdgpu_framebuffer_init(struct drm_device *dev,
int amdgpu_framebuffer_init(struct drm_device *dev,
			     struct amdgpu_framebuffer *rfb,
			     struct amdgpu_framebuffer *rfb,
+8 −11
Original line number Original line Diff line number Diff line
@@ -694,12 +694,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
					  unsigned flags,
					  unsigned flags,
					  const struct drm_display_mode *mode)
					  const struct drm_display_mode *mode)
{
{
	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
	struct timeval tv_etime;
	struct timeval tv_etime;
	ktime_t stime, etime;
	ktime_t stime, etime;
	int vbl_status;
	int vbl_status;
	int vpos, hpos, i;
	int vpos, hpos, i;
	int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
	int delta_ns, duration_ns;
	bool invbl;
	bool invbl;


	if (pipe >= dev->num_crtcs) {
	if (pipe >= dev->num_crtcs) {
@@ -713,15 +712,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
		return -EIO;
		return -EIO;
	}
	}


	/* Durations of frames, lines, pixels in nanoseconds. */
	framedur_ns = vblank->framedur_ns;
	linedur_ns  = vblank->linedur_ns;
	pixeldur_ns = vblank->pixeldur_ns;

	/* If mode timing undefined, just return as no-op:
	/* If mode timing undefined, just return as no-op:
	 * Happens during initial modesetting of a crtc.
	 * Happens during initial modesetting of a crtc.
	 */
	 */
	if (framedur_ns == 0) {
	if (mode->crtc_clock == 0) {
		DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
		DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
		return -EAGAIN;
		return -EAGAIN;
	}
	}
@@ -738,8 +732,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
		 * Get vertical and horizontal scanout position vpos, hpos,
		 * Get vertical and horizontal scanout position vpos, hpos,
		 * and bounding timestamps stime, etime, pre/post query.
		 * and bounding timestamps stime, etime, pre/post query.
		 */
		 */
		vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, &vpos,
		vbl_status = dev->driver->get_scanout_position(dev, pipe, flags,
							       &hpos, &stime, &etime);
							       &vpos, &hpos,
							       &stime, &etime,
							       mode);


		/* Return as no-op if scanout query unsupported or failed. */
		/* Return as no-op if scanout query unsupported or failed. */
		if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
		if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
@@ -776,7 +772,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
	 * since start of scanout at first display scanline. delta_ns
	 * since start of scanout at first display scanline. delta_ns
	 * can be negative if start of scanout hasn't happened yet.
	 * can be negative if start of scanout hasn't happened yet.
	 */
	 */
	delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
	delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos),
			   mode->crtc_clock);


	if (!drm_timestamp_monotonic)
	if (!drm_timestamp_monotonic)
		etime = ktime_mono_to_real(etime);
		etime = ktime_mono_to_real(etime);
+2 −2
Original line number Original line Diff line number Diff line
@@ -648,12 +648,12 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)


static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
				    unsigned int flags, int *vpos, int *hpos,
				    unsigned int flags, int *vpos, int *hpos,
				    ktime_t *stime, ktime_t *etime)
				    ktime_t *stime, ktime_t *etime,
				    const struct drm_display_mode *mode)
{
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	const struct drm_display_mode *mode = &intel_crtc->base.hwmode;
	int position;
	int position;
	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
	bool in_vbl = true;
	bool in_vbl = true;
+2 −1
Original line number Original line Diff line number Diff line
@@ -133,7 +133,8 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,


int
int
nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
			   int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
			   int *vpos, int *hpos, ktime_t *stime, ktime_t *etime,
			   const struct drm_display_mode *mode)
{
{
	struct drm_crtc *crtc;
	struct drm_crtc *crtc;


Loading