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: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> [danvet: Squash in fixup from Thierry Reding for amdgpu.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
eba1f35dfe
commit
3bb403bf42
11 changed files with 43 additions and 34 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,8 @@ void nouveau_display_resume(struct drm_device *dev, bool runtime);
|
||||||
int nouveau_display_vblank_enable(struct drm_device *, int);
|
int nouveau_display_vblank_enable(struct drm_device *, int);
|
||||||
void nouveau_display_vblank_disable(struct drm_device *, int);
|
void nouveau_display_vblank_disable(struct drm_device *, int);
|
||||||
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
|
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
|
||||||
int *, int *, ktime_t *, ktime_t *);
|
int *, int *, ktime_t *, ktime_t *,
|
||||||
|
const struct drm_display_mode *);
|
||||||
int nouveau_display_vblstamp(struct drm_device *, int, int *,
|
int nouveau_display_vblstamp(struct drm_device *, int, int *,
|
||||||
struct timeval *, unsigned);
|
struct timeval *, unsigned);
|
||||||
|
|
||||||
|
|
|
@ -323,7 +323,8 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)
|
||||||
*/
|
*/
|
||||||
if (update_pending &&
|
if (update_pending &&
|
||||||
(DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
|
(DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
|
||||||
&vpos, &hpos, NULL, NULL)) &&
|
&vpos, &hpos, NULL, NULL,
|
||||||
|
&rdev->mode_info.crtcs[crtc_id]->base.hwmode)) &&
|
||||||
((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
|
((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
|
||||||
(vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
|
(vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
|
||||||
/* crtc didn't flip in this target vblank interval,
|
/* crtc didn't flip in this target vblank interval,
|
||||||
|
@ -1799,7 +1800,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
|
int radeon_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 stat_crtc = 0, vbl = 0, position = 0;
|
u32 stat_crtc = 0, vbl = 0, position = 0;
|
||||||
int vbl_start, vbl_end, vtotal, ret = 0;
|
int vbl_start, vbl_end, vtotal, ret = 0;
|
||||||
|
@ -1914,7 +1916,7 @@ int radeon_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 = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
|
vbl_start = mode->crtc_vdisplay;
|
||||||
vbl_end = 0;
|
vbl_end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1930,7 +1932,7 @@ int radeon_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 = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
|
vtotal = mode->crtc_vtotal;
|
||||||
*vpos = *vpos - vtotal;
|
*vpos = *vpos - vtotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1952,8 +1954,8 @@ int radeon_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 = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
|
vbl_start = mode->crtc_vdisplay;
|
||||||
vtotal = rdev->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;
|
||||||
|
|
|
@ -126,8 +126,9 @@ struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
|
||||||
int flags);
|
int flags);
|
||||||
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
|
extern int radeon_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 *etime);
|
ktime_t *stime, ktime_t *etime,
|
||||||
|
const struct drm_display_mode *mode);
|
||||||
extern bool radeon_is_px(struct drm_device *dev);
|
extern bool radeon_is_px(struct drm_device *dev);
|
||||||
extern const struct drm_ioctl_desc radeon_ioctls_kms[];
|
extern const struct drm_ioctl_desc radeon_ioctls_kms[];
|
||||||
extern int radeon_max_kms_ioctl;
|
extern int radeon_max_kms_ioctl;
|
||||||
|
|
|
@ -876,8 +876,9 @@ extern void radeon_cursor_reset(struct drm_crtc *crtc);
|
||||||
|
|
||||||
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
|
extern int radeon_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 *etime);
|
ktime_t *stime, ktime_t *etime,
|
||||||
|
const struct drm_display_mode *mode);
|
||||||
|
|
||||||
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
||||||
extern struct edid *
|
extern struct edid *
|
||||||
|
|
|
@ -1733,7 +1733,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
|
||||||
*/
|
*/
|
||||||
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
|
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
|
||||||
if (rdev->pm.active_crtcs & (1 << crtc)) {
|
if (rdev->pm.active_crtcs & (1 << crtc)) {
|
||||||
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);
|
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0,
|
||||||
|
&vpos, &hpos, NULL, NULL,
|
||||||
|
&rdev->mode_info.crtcs[crtc]->base.hwmode);
|
||||||
if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
|
if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
|
||||||
!(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
|
!(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
|
||||||
in_vbl = false;
|
in_vbl = false;
|
||||||
|
|
|
@ -482,6 +482,7 @@ struct drm_driver {
|
||||||
* scanout position query. Can be NULL to skip timestamp.
|
* scanout position query. Can be NULL to skip timestamp.
|
||||||
* \param *etime Target location for timestamp taken immediately after
|
* \param *etime Target location for timestamp taken immediately after
|
||||||
* scanout position query. Can be NULL to skip timestamp.
|
* scanout position query. Can be NULL to skip timestamp.
|
||||||
|
* \param mode Current display timings.
|
||||||
*
|
*
|
||||||
* Returns vpos as a positive number while in active scanout area.
|
* Returns vpos as a positive number while in active scanout area.
|
||||||
* Returns vpos as a negative number inside vblank, counting the number
|
* Returns vpos as a negative number inside vblank, counting the number
|
||||||
|
@ -499,8 +500,9 @@ struct drm_driver {
|
||||||
*/
|
*/
|
||||||
int (*get_scanout_position) (struct drm_device *dev, int crtc,
|
int (*get_scanout_position) (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 *etime);
|
ktime_t *stime, ktime_t *etime,
|
||||||
|
const struct drm_display_mode *mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by \c drm_get_last_vbltimestamp. Should return a precise
|
* Called by \c drm_get_last_vbltimestamp. Should return a precise
|
||||||
|
|
Loading…
Add table
Reference in a new issue