public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: simona@ffwll.ch, michel.daenzer@mailbox.org,
	louis.chauvet@bootlin.com, ville.syrjala@linux.intel.com,
	jani.nikula@intel.com, mhklkml@zohomail.com,
	maarten.lankhorst@linux.intel.com, mripard@kernel.org,
	airlied@gmail.com
Cc: dri-devel@lists.freedesktop.org, amd-gfx@lists.freedesktop.org,
	virtualization@lists.linux.dev,
	Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH 2/7] drm/vblank: timer: Fix timestamp calculation
Date: Mon,  1 Jun 2026 16:08:30 +0200	[thread overview]
Message-ID: <20260601141922.91498-3-tzimmermann@suse.de> (raw)
In-Reply-To: <20260601141922.91498-1-tzimmermann@suse.de>

In drm_crtc_vblank_get_vblank_timeout(), return the timestamp of the
first visible scanline after the last vblank timeout. This is what the
caller expects.

A vblank phase starts with a vblank timeout. At this point the display
is blanked for several scanlines. Afterwards the display is unblanked
until the next vblank timeout occurs. The display content is only visible
during that second part.

The current implementation of drm_crtc_vblank_get_vblank_timeout()
returns the timestamp of the last vblank timeout that started the current
vblank phase. But the display only unblanks after 20 to 30 percent of
the overall frame duration. The returned timestamp is therefore too early.

The next vblank timeout is already known when calculating the returned
timestamp. Instead of subtracting the duration of a full frame from the
value, only subtract the duration of the active, visible part. The result
is the timestamp of the first visible scanline, as expected by the caller.

This bug was not introduced by the generic vblank timer. It appears that
the get_vblank_timeout logic has always been buggy since it was first
added in commit 3a0709928b17 ("drm/vkms: Add vblank events simulated by
hrtimers").

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_vblank.c | 32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 96d70c3d4522..d52df247d04e 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -2293,10 +2293,19 @@ EXPORT_SYMBOL(drm_crtc_vblank_cancel_timer);
  */
 bool drm_crtc_vblank_get_vblank_timeout(struct drm_crtc *crtc, ktime_t *vblank_time)
 {
+	struct drm_device *dev = crtc->dev;
 	struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
 	struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer;
+	const struct drm_display_mode *mode;
 	u64 cur_count;
 	ktime_t cur_time;
+	s64 framedur_ns;
+	s64 activedur_ns;
+
+	if (drm_drv_uses_atomic_modeset(dev))
+		mode = &vblank->hwmode;
+	else
+		mode = &crtc->hwmode;
 
 	if (!READ_ONCE(vblank->enabled))
 		return false;
@@ -2312,17 +2321,26 @@ bool drm_crtc_vblank_get_vblank_timeout(struct drm_crtc *crtc, ktime_t *vblank_t
 		*vblank_time = READ_ONCE(vtimer->timer.node.expires);
 	} while (cur_count != drm_crtc_vblank_count_and_time(crtc, &cur_time));
 
-	if (drm_WARN_ON(crtc->dev, !ktime_compare(*vblank_time, cur_time)))
+	if (drm_WARN_ON(dev, !ktime_compare(*vblank_time, cur_time)))
 		return false; /* Already expired */
 
+	framedur_ns = vblank->framedur_ns;
+
 	/*
-	 * To prevent races we roll the hrtimer forward before we do any
-	 * interrupt processing - this is how real hw works (the interrupt
-	 * is only generated after all the vblank registers are updated)
-	 * and what the vblank core expects. Therefore we need to always
-	 * correct the timestamp by one frame.
+	 * To prevent races we rolled the hrtimer forward before we did any
+	 * timeout processing - this is how real hw works (the interrupt is
+	 * only generated after all the vblank registers are updated) and what
+	 * the vblank core expects.
+	 *
+	 * Therefore we always need to correct the timestamp. The returned
+	 * time should be the time of the first active scanline after the
+	 * previous vblank. Hence subtract the active phase's duration from
+	 * the next expiration time.
 	 */
-	*vblank_time = ktime_sub(*vblank_time, vtimer->interval);
+	if (drm_WARN_ON(dev, !mode->crtc_vtotal))
+		return false;
+	activedur_ns = div_s64(framedur_ns * mode->crtc_vdisplay, mode->crtc_vtotal);
+	*vblank_time = ktime_sub_ns(*vblank_time, activedur_ns);
 
 	return true;
 }
-- 
2.54.0


  parent reply	other threads:[~2026-06-01 14:19 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-01 14:08 [PATCH 0/7] drm/vblank: timer: Fix timestamps and improve reliabilty Thomas Zimmermann
2026-06-01 14:08 ` [PATCH 1/7] drm/vblank: timer: Return success status from get_vblank_timeout Thomas Zimmermann
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` Thomas Zimmermann [this message]
2026-06-01 16:24   ` [PATCH 2/7] drm/vblank: timer: Fix timestamp calculation Michel Dänzer
2026-06-01 17:30     ` Thomas Zimmermann
2026-06-02 14:14       ` Michel Dänzer
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` [PATCH 3/7] drm/vblank: timer: Use absolute timer since boot Thomas Zimmermann
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` [PATCH 4/7] drm/vblank: timer: Reorganize get_vblank_timeout Thomas Zimmermann
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` [PATCH 5/7] drm/vblank: timer: Estimate vblank timeout if timer is disabled Thomas Zimmermann
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` [PATCH 6/7] drm/vblank: timer: Verify that expiry time is in the future Thomas Zimmermann
2026-06-04  4:03   ` Claude review: " Claude Code Review Bot
2026-06-01 14:08 ` [PATCH 7/7] drm/vblank: timer: Avoid reading the vblank time unnecessarily Thomas Zimmermann
2026-06-04  4:04   ` Claude review: " Claude Code Review Bot
2026-06-04  4:03 ` Claude review: drm/vblank: timer: Fix timestamps and improve reliabilty Claude Code Review Bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260601141922.91498-3-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=airlied@gmail.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jani.nikula@intel.com \
    --cc=louis.chauvet@bootlin.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mhklkml@zohomail.com \
    --cc=michel.daenzer@mailbox.org \
    --cc=mripard@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=ville.syrjala@linux.intel.com \
    --cc=virtualization@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox