On Mon, Dec 01, 2025 at 03:24:56PM +0200, Jouni Högander wrote:
> According to bspec selective fetch is not supported with async flips and
> instructing full frame update on async flip.
> 
> v3:
>   - rebase
>   - fix old_crtc_state->pipe_srcsz_early_tpt
>   - fix using intel_atomic_get_new_crtc_state
> v2:
>   - check also crtc_state->async_flip_planes in
>     psr2_sel_fetch_plane_state_supported
> 
> Bspec: 55229
> Signed-off-by: Jouni Högander <[email protected]>
> ---
>  drivers/gpu/drm/i915/display/intel_psr.c | 72 ++++++++++++++----------
>  1 file changed, 41 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c 
> b/drivers/gpu/drm/i915/display/intel_psr.c
> index 15ef3b6caad6..53cf292247d7 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -2728,13 +2728,20 @@ intel_psr2_sel_fetch_et_alignment(struct 
> intel_atomic_state *state,
>   * Plane scaling and rotation is not supported by selective fetch and both
>   * properties can change without a modeset, so need to be check at every
>   * atomic commit.
> + *
> + * If plane was having async flip previously we can't use selective
> + * fetch as we don't know if the flip is completed.
>   */
> -static bool psr2_sel_fetch_plane_state_supported(const struct 
> intel_plane_state *plane_state)
> +static bool psr2_sel_fetch_plane_state_supported(const struct 
> intel_crtc_state *old_crtc_state,
> +                                              const struct intel_plane_state 
> *plane_state)
>  {
> +     struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
> +
>       if (plane_state->uapi.dst.y1 < 0 ||
>           plane_state->uapi.dst.x1 < 0 ||
>           plane_state->scaler_id >= 0 ||
> -         plane_state->hw.rotation != DRM_MODE_ROTATE_0)
> +         plane_state->hw.rotation != DRM_MODE_ROTATE_0 ||
> +         old_crtc_state->async_flip_planes & plane->id)

Why are you looking at the old crtc state? There should be nothing of
interest to us there.

>               return false;
>  
>       return true;
> @@ -2749,7 +2756,8 @@ static bool psr2_sel_fetch_plane_state_supported(const 
> struct intel_plane_state
>   */
>  static bool psr2_sel_fetch_pipe_state_supported(const struct 
> intel_crtc_state *crtc_state)
>  {
> -     if (crtc_state->scaler_state.scaler_id >= 0)
> +     if (crtc_state->scaler_state.scaler_id >= 0 ||
> +         crtc_state->uapi.async_flip)

I think just checking crtc_state->async_flip_planes!=0 here should be
sufficient. The rest of the patch seems unnecessary.

On a related note, someone should add a new igt that does async flips
while eg. the cursor is enabled and overlapping the plane doing the
async flips. That's basically how I noticed the problem in the first
place (with Xorg), so would be good to have an igt to make sure we
don't break this in the future.

>               return false;
>  
>       return true;
> @@ -2808,24 +2816,25 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>                               struct intel_crtc *crtc)
>  {
>       struct intel_display *display = to_intel_display(state);
> -     struct intel_crtc_state *crtc_state = 
> intel_atomic_get_new_crtc_state(state, crtc);
> +     struct intel_crtc_state *new_crtc_state = 
> intel_atomic_get_new_crtc_state(state, crtc);
> +     struct intel_crtc_state *old_crtc_state = 
> intel_atomic_get_old_crtc_state(state, crtc);
>       struct intel_plane_state *new_plane_state, *old_plane_state;
>       struct intel_plane *plane;
>       bool full_update = false, cursor_in_su_area = false;
>       int i, ret;
>  
> -     if (!crtc_state->enable_psr2_sel_fetch)
> +     if (!new_crtc_state->enable_psr2_sel_fetch)
>               return 0;
>  
> -     if (!psr2_sel_fetch_pipe_state_supported(crtc_state)) {
> +     if (!psr2_sel_fetch_pipe_state_supported(new_crtc_state)) {
>               full_update = true;
>               goto skip_sel_fetch_set_loop;
>       }
>  
> -     crtc_state->psr2_su_area.x1 = 0;
> -     crtc_state->psr2_su_area.y1 = -1;
> -     crtc_state->psr2_su_area.x2 = drm_rect_width(&crtc_state->pipe_src);
> -     crtc_state->psr2_su_area.y2 = -1;
> +     new_crtc_state->psr2_su_area.x1 = 0;
> +     new_crtc_state->psr2_su_area.y1 = -1;
> +     new_crtc_state->psr2_su_area.x2 = 
> drm_rect_width(&new_crtc_state->pipe_src);
> +     new_crtc_state->psr2_su_area.y2 = -1;
>  
>       /*
>        * Calculate minimal selective fetch area of each plane and calculate
> @@ -2838,14 +2847,14 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>               struct drm_rect src, damaged_area = { .x1 = 0, .y1 = -1,
>                                                     .x2 = INT_MAX };
>  
> -             if (new_plane_state->hw.crtc != crtc_state->uapi.crtc)
> +             if (new_plane_state->hw.crtc != new_crtc_state->uapi.crtc)
>                       continue;
>  
>               if (!new_plane_state->uapi.visible &&
>                   !old_plane_state->uapi.visible)
>                       continue;
>  
> -             if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) {
> +             if (!psr2_sel_fetch_plane_state_supported(old_crtc_state, 
> new_plane_state)) {
>                       full_update = true;
>                       break;
>               }
> @@ -2861,23 +2870,23 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>                       if (old_plane_state->uapi.visible) {
>                               damaged_area.y1 = old_plane_state->uapi.dst.y1;
>                               damaged_area.y2 = old_plane_state->uapi.dst.y2;
> -                             clip_area_update(&crtc_state->psr2_su_area, 
> &damaged_area,
> -                                              &crtc_state->pipe_src);
> +                             clip_area_update(&new_crtc_state->psr2_su_area, 
> &damaged_area,
> +                                              &new_crtc_state->pipe_src);
>                       }
>  
>                       if (new_plane_state->uapi.visible) {
>                               damaged_area.y1 = new_plane_state->uapi.dst.y1;
>                               damaged_area.y2 = new_plane_state->uapi.dst.y2;
> -                             clip_area_update(&crtc_state->psr2_su_area, 
> &damaged_area,
> -                                              &crtc_state->pipe_src);
> +                             clip_area_update(&new_crtc_state->psr2_su_area, 
> &damaged_area,
> +                                              &new_crtc_state->pipe_src);
>                       }
>                       continue;
>               } else if (new_plane_state->uapi.alpha != 
> old_plane_state->uapi.alpha) {
>                       /* If alpha changed mark the whole plane area as 
> damaged */
>                       damaged_area.y1 = new_plane_state->uapi.dst.y1;
>                       damaged_area.y2 = new_plane_state->uapi.dst.y2;
> -                     clip_area_update(&crtc_state->psr2_su_area, 
> &damaged_area,
> -                                      &crtc_state->pipe_src);
> +                     clip_area_update(&new_crtc_state->psr2_su_area, 
> &damaged_area,
> +                                      &new_crtc_state->pipe_src);
>                       continue;
>               }
>  
> @@ -2893,7 +2902,8 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>               damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1;
>               damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1;
>  
> -             clip_area_update(&crtc_state->psr2_su_area, &damaged_area, 
> &crtc_state->pipe_src);
> +             clip_area_update(&new_crtc_state->psr2_su_area, &damaged_area,
> +                              &new_crtc_state->pipe_src);
>       }
>  
>       /*
> @@ -2902,7 +2912,7 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>        * should identify cases where this happens and fix the area
>        * calculation for those.
>        */
> -     if (crtc_state->psr2_su_area.y1 == -1) {
> +     if (new_crtc_state->psr2_su_area.y1 == -1) {
>               drm_info_once(display->drm,
>                             "Selective fetch area calculation failed in pipe 
> %c\n",
>                             pipe_name(crtc->pipe));
> @@ -2912,7 +2922,7 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>       if (full_update)
>               goto skip_sel_fetch_set_loop;
>  
> -     intel_psr_apply_su_area_workarounds(crtc_state);
> +     intel_psr_apply_su_area_workarounds(new_crtc_state);
>  
>       ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
>       if (ret)
> @@ -2926,7 +2936,7 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>        */
>       intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area);
>  
> -     intel_psr2_sel_fetch_pipe_alignment(crtc_state);
> +     intel_psr2_sel_fetch_pipe_alignment(new_crtc_state);
>  
>       /*
>        * Now that we have the pipe damaged area check if it intersect with
> @@ -2937,11 +2947,11 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>               struct drm_rect *sel_fetch_area, inter;
>               struct intel_plane *linked = 
> new_plane_state->planar_linked_plane;
>  
> -             if (new_plane_state->hw.crtc != crtc_state->uapi.crtc ||
> +             if (new_plane_state->hw.crtc != new_crtc_state->uapi.crtc ||
>                   !new_plane_state->uapi.visible)
>                       continue;
>  
> -             inter = crtc_state->psr2_su_area;
> +             inter = new_crtc_state->psr2_su_area;
>               sel_fetch_area = &new_plane_state->psr2_sel_fetch_area;
>               if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) {
>                       sel_fetch_area->y1 = -1;
> @@ -2951,12 +2961,12 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>                        * disable it
>                        */
>                       if 
> (drm_rect_height(&old_plane_state->psr2_sel_fetch_area) > 0)
> -                             crtc_state->update_planes |= BIT(plane->id);
> +                             new_crtc_state->update_planes |= BIT(plane->id);
>  
>                       continue;
>               }
>  
> -             if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) {
> +             if (!psr2_sel_fetch_plane_state_supported(old_crtc_state, 
> new_plane_state)) {
>                       full_update = true;
>                       break;
>               }
> @@ -2964,7 +2974,7 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>               sel_fetch_area = &new_plane_state->psr2_sel_fetch_area;
>               sel_fetch_area->y1 = inter.y1 - new_plane_state->uapi.dst.y1;
>               sel_fetch_area->y2 = inter.y2 - new_plane_state->uapi.dst.y1;
> -             crtc_state->update_planes |= BIT(plane->id);
> +             new_crtc_state->update_planes |= BIT(plane->id);
>  
>               /*
>                * Sel_fetch_area is calculated for UV plane. Use
> @@ -2981,14 +2991,14 @@ int intel_psr2_sel_fetch_update(struct 
> intel_atomic_state *state,
>                       linked_sel_fetch_area = 
> &linked_new_plane_state->psr2_sel_fetch_area;
>                       linked_sel_fetch_area->y1 = sel_fetch_area->y1;
>                       linked_sel_fetch_area->y2 = sel_fetch_area->y2;
> -                     crtc_state->update_planes |= BIT(linked->id);
> +                     new_crtc_state->update_planes |= BIT(linked->id);
>               }
>       }
>  
>  skip_sel_fetch_set_loop:
> -     psr2_man_trk_ctl_calc(crtc_state, full_update);
> -     crtc_state->pipe_srcsz_early_tpt =
> -             psr2_pipe_srcsz_early_tpt_calc(crtc_state, full_update);
> +     psr2_man_trk_ctl_calc(new_crtc_state, full_update);
> +     new_crtc_state->pipe_srcsz_early_tpt =
> +             psr2_pipe_srcsz_early_tpt_calc(new_crtc_state, full_update);
>       return 0;
>  }
>  
> -- 
> 2.43.0

-- 
Ville Syrjälä
Intel

Reply via email to