[PATCH 4/4] drm/amd/display: Make pageflip event delivery compatible with VRR.

Kazlauskas, Nicholas Nicholas.Kazlauskas at amd.com
Tue Mar 19 13:05:34 UTC 2019


On 3/18/19 1:19 PM, Mario Kleiner wrote:
> We want vblank counts and timestamps of flip completion as sent
> in pageflip completion events to be consistent with the vblank
> count and timestamp of the vblank of flip completion, like in non
> VRR mode.
> 
> In VRR mode, drm_update_vblank_count() - and thereby vblank
> count and timestamp updates - must be delayed until after the
> end of front-porch of each vblank, as it is only safe to
> calculate vblank timestamps outside of the front-porch, when
> we actually know when the vblank will end or has ended.
> 
> The function drm_update_vblank_count() which updates timestamps
> and counts gets called by drm_crtc_accurate_vblank_count() or by
> drm_crtc_handle_vblank().
> 
> Therefore we must make sure that pageflip events for a completed
> flip are only sent out after drm_crtc_accurate_vblank_count() or
> drm_crtc_handle_vblank() is executed, after end of front-porch
> for the vblank of flip completion.
> 
> Two cases:
> 
> a) Pageflip irq handler executes inside front-porch:
>     In this case we must defer sending pageflip events until
>     drm_crtc_handle_vblank() executes after end of front-porch,
>     and thereby calculates proper vblank count and timestamp.
>     Iow. the pflip irq handler must just arm a pageflip event
>     to be sent out by drm_crtc_handle_vblank() later on.
> 
> b) Pageflip irq handler executes after end of front-porch, e.g.,
>     after flip completion in back-porch or due to a massively
>     delayed handler invocation into the active scanout of the new
>     frame. In this case we can call drm_crtc_accurate_vblank_count()
>     to safely force calculation of a proper vblank count and
>     timestamp, and must send the pageflip completion event
>     ourselves from the pageflip irq handler.
> 
>     This is the same behaviour as needed for standard fixed refresh
>     rate mode.
> 
> To decide from within pageflip handler if we are in case a) or b),
> we check the current scanout position against the boundary of
> front-porch. In non-VRR mode we just do what we did in the past.
> 
> Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas at amd.com>

This patch looks fine to me for the most part, but it's still pending on 
the other patches in the series.

> ---
>   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 68 ++++++++++++++++++-----
>   1 file changed, 55 insertions(+), 13 deletions(-)
> 
> 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 555d9e9f..499284d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -263,6 +263,10 @@ static void dm_pflip_high_irq(void *interrupt_params)
>   	struct common_irq_params *irq_params = interrupt_params;
>   	struct amdgpu_device *adev = irq_params->adev;
>   	unsigned long flags;
> +	struct drm_pending_vblank_event *e;
> +	struct dm_crtc_state *acrtc_state;
> +	uint32_t vpos, hpos, v_blank_start, v_blank_end;
> +	bool vrr_active;
>   
>   	amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
>   
> @@ -285,18 +289,57 @@ static void dm_pflip_high_irq(void *interrupt_params)
>   		return;
>   	}
>   
> -	/* Update to correct count(s) if racing with vblank irq */
> -	drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
> +	/* page flip completed. */
> +	e = amdgpu_crtc->event;
> +	amdgpu_crtc->event = NULL;
>   
> -	/* wake up userspace */
> -	if (amdgpu_crtc->event) {
> -		drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event);
> +	if (!e)
> +		WARN_ON(1);
>   
> -		/* page flip completed. clean up */
> -		amdgpu_crtc->event = NULL;
> +	acrtc_state = to_dm_crtc_state(amdgpu_crtc->base.state);
> +	vrr_active = amdgpu_dm_vrr_active(acrtc_state);
> +
> +	/* Fixed refresh rate, or VRR scanout position outside front-porch? */
> +	if (!vrr_active ||
> +	    !dc_stream_get_scanoutpos(acrtc_state->stream, &v_blank_start,
> +				      &v_blank_end, &hpos, &vpos) ||
> +	    (vpos < v_blank_start)) {
> +		/* Update to correct count and vblank timestamp if racing with
> +		 * vblank irq. This also updates to the correct vblank timestamp
> +		 * even in VRR mode, as scanout is past the front-porch atm.
> +		 */
> +		drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
>   
> -	} else
> -		WARN_ON(1);
> +		/* Wake up userspace by sending the pageflip event with proper
> +		 * count and timestamp of vblank of flip completion.
> +		 */
> +		if (e) {
> +			drm_crtc_send_vblank_event(&amdgpu_crtc->base, e);
> +
> +			/* Event sent, so done with vblank for this flip */
> +			drm_crtc_vblank_put(&amdgpu_crtc->base);
> +		}
> +	} else if (e) {
> +		/* VRR active and inside front-porch: vblank count and
> +		 * timestamp for pageflip event will only be up to date after
> +		 * drm_crtc_handle_vblank() has been executed from late vblank
> +		 * irq handler after start of back-porch (vline 0). We queue the
> +		 * pageflip event for send-out by drm_crtc_handle_vblank() with
> +		 * updated timestamp and count, once it runs after us.
> +		 *
> +		 * We need to open-code this instead of using the helper
> +		 * drm_crtc_arm_vblank_event(), as that helper would
> +		 * call drm_crtc_accurate_vblank_count(), which we must
> +		 * not call in VRR mode while we are in front-porch!
> +		 */
> +
> +		/* sequence will be replaced by real count during send-out. */
> +		e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base);
> +		e->pipe = amdgpu_crtc->crtc_id;
> +
> +		list_add_tail(&e->base.link, &adev->ddev->vblank_event_list);
> +		e = NULL;

I guess drm_crtc_vblank_off handles sending any leftover events here if 
there are any if the IRQ gets disabled incorrectly.

I wonder why we never just used this list in the first place for 
pageflip vblank event handling instead of the locking and NULL set. 
Though I suppose it's more useful to use this now for VRR vblank handling.

> +	}
>   
>   	/* Keep track of vblank of this flip for flip throttling. We use the
>   	 * cooked hw counter, as that one incremented at start of this vblank
> @@ -309,10 +352,9 @@ static void dm_pflip_high_irq(void *interrupt_params)
>   	amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
>   	spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
>   
> -	DRM_DEBUG_DRIVER("%s - crtc :%d[%p], pflip_stat:AMDGPU_FLIP_NONE\n",
> -					__func__, amdgpu_crtc->crtc_id, amdgpu_crtc);
> -
> -	drm_crtc_vblank_put(&amdgpu_crtc->base);
> +	DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
> +			 amdgpu_crtc->crtc_id, amdgpu_crtc,
> +			 vrr_active, (int) !e);

The debug output for this is a little strange, but I guess it makes it 
makes as much sense as the original did. I'm glad the __func__ is gone 
at least.

>   }
>   
>   static void dm_vupdate_high_irq(void *interrupt_params)
> 



More information about the amd-gfx mailing list