drm/amd/display: Use vrr friendly pageflip throttling in DC. [Linux 5.0]

This Linux kernel change "drm/amd/display: Use vrr friendly pageflip throttling in DC" is included in the Linux 5.0 release. This change is authored by Mario Kleiner <mario.kleiner.de [at] gmail.com> on Wed Jan 30 06:04:46 2019 +0100. The commit for this change in Linux stable tree is d637166 (patch).

drm/amd/display: Use vrr friendly pageflip throttling in DC.

In VRR mode, keep track of the vblank count of the last
completed pageflip in amdgpu_crtc->last_flip_vblank, as
recorded in the pageflip completion handler after each
completed flip.

Use that count to prevent mmio programming a new pageflip
within the same vblank in which the last pageflip completed,
iow. to throttle pageflips to at most one flip per video
frame, while at the same time allowing to request a flip
not only before start of vblank, but also anywhere within
vblank.

The old logic did the same, and made sense for regular fixed
refresh rate flipping, but in vrr mode it prevents requesting
a flip anywhere inside the possibly huge vblank, thereby
reducing framerate in vrr mode instead of improving it, by
delaying a slightly delayed flip requests up to a maximum
vblank duration + 1 scanout duration. This would limit VRR
usefulness to only help applications with a very high GPU
demand, which can submit the flip request before start of
vblank, but then have to wait long for fences to complete.

With this method a flip can be both requested and - after
fences have completed - executed, ie. it doesn't matter if
the request (amdgpu_dm_do_flip()) gets delayed until deep
into the extended vblank due to cpu execution delays. This
also allows clients which want to regulate framerate within
the vrr range a much more fine-grained control of flip timing,
a feature that might be useful for video playback, and is
very useful for neuroscience/vision research applications.

In regular non-VRR mode, retain the old flip submission
behavior. This to keep flip scheduling for fullscreen X11/GLX
OpenGL clients intact, if they use the GLX_OML_sync_control
extensions glXSwapBufferMscOML(, ..., target_msc,...) function
with a specific target_msc target vblank count.

glXSwapBuffersMscOML() or DRI3/Present PresentPixmap() will
not flip at the proper target_msc for a non-zero target_msc
if VRR mode is active with this patch. They'd often flip one
frame too early. However, this limitation should not matter
much in VRR mode, as scheduling based on vblank counts is
pretty futile/unusable under variable refresh duration
anyway, so no real extra harm is done.

Signed-off-by: Mario Kleiner <[email protected]>
Cc: Nicholas Kazlauskas <[email protected]>
Cc: Harry Wentland <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Michel Dänzer <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>

There are 28 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h          |  1 +
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 27 +++++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index aadd0fa..3aa42c6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -405,6 +405,7 @@ struct amdgpu_crtc {
    struct amdgpu_flip_work *pflip_works;
    enum amdgpu_flip_status pflip_status;
    int deferred_flip_completion;
+   u64 last_flip_vblank;
    /* pll sharing */
    struct amdgpu_atom_ss ss;
    bool ss_enabled;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 5296b8f..636d14a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -303,12 +303,11 @@ static void dm_pflip_high_irq(void *interrupt_params)
        return;
    }

+   /* Update to correct count(s) if racing with vblank irq */
+   amdgpu_crtc->last_flip_vblank = drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);

    /* wake up userspace */
    if (amdgpu_crtc->event) {
-       /* Update to correct count(s) if racing with vblank irq */
-       drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
-
        drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event);

        /* page flip completed. clean up */
@@ -4828,6 +4827,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
            to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
    int planes_count = 0;
    unsigned long flags;
+   u64 last_flip_vblank;
+   bool vrr_active = acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE;

    /* update planes when needed */
    for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
@@ -4859,6 +4860,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
            /* In commit tail framework this cannot happen */
            WARN_ON(1);
        }
+
+       /* For variable refresh rate mode only:
+        * Get vblank of last completed flip to avoid > 1 vrr flips per
+        * video frame by use of throttling, but allow flip programming
+        * anywhere in the possibly large variable vrr vblank interval
+        * for fine-grained flip timing control and more opportunity to
+        * avoid stutter on late submission of amdgpu_dm_do_flip() calls.
+        */
+       last_flip_vblank = acrtc_attach->last_flip_vblank;
+
        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);

        if (!pflip_needed || plane->type == DRM_PLANE_TYPE_OVERLAY) {
@@ -4882,10 +4893,18 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
            if (plane->type == DRM_PLANE_TYPE_PRIMARY)
                drm_crtc_vblank_get(crtc);

+           /* Use old throttling in non-vrr fixed refresh rate mode
+            * to keep flip scheduling based on target vblank counts
+            * working in a backwards compatible way, e.g., clients
+            * using GLX_OML_sync_control extension.
+            */
+           if (!vrr_active)
+               last_flip_vblank = drm_crtc_vblank_count(crtc);
+
            amdgpu_dm_do_flip(
                crtc,
                fb,
-               (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
+               (uint32_t) last_flip_vblank + *wait_for_vblank,
                dc_state);
        }

Leave a Reply

Your email address will not be published. Required fields are marked *