dm_plane_color_pipeline_active() iterates every colorop state in the atomic commit, so colorops of a pipeline that userspace deactivated via plane COLOR_PIPELINE are still taken into account, even though their BYPASS property is irrelevant once the pipeline is off. Walk the color pipeline of the plane state under evaluation instead, falling back to the committed colorop state when a colorop isn't in the atomic commit.
Reported-by: Sashiko <[email protected]> Fixes: d3a549f4df78 ("drm/amd/display: Use overlay cursor when color pipeline is active") Acked-by: Harry Wentland <[email protected]> Signed-off-by: Melissa Wen <[email protected]> --- v4: - drop the ternary and add just a warn_on since both current callers iterate planes already in the atomic state. (John H.) - explain the reason to use commited colorop (John H.) --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 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 d0e612371c8f..384541b9ac9c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6551,9 +6551,9 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state, struct dr * @use_old: if true, inspect the old colorop states; otherwise the new ones * * A color pipeline may be selected (color_pipeline != NULL) but still is - * inactive if every colorop in the chain is bypassed. Only return - * true when at least one colorop has bypass == false, meaning the cursor - * would be subjected to the transformation in native mode. + * inactive if every colorop in the chain is bypassed. Only return true when at + * least one colorop has bypass == false, meaning the cursor would be subjected + * to the transformation in native mode. * * Return: true if the pipeline modifies pixels, false otherwise. */ @@ -6561,18 +6561,33 @@ static bool dm_plane_color_pipeline_active(struct drm_atomic_commit *state, struct drm_plane *plane, bool use_old) { + struct drm_plane_state *plane_state = use_old ? + drm_atomic_get_old_plane_state(state, plane) : + drm_atomic_get_new_plane_state(state, plane); struct drm_colorop *colorop; - struct drm_colorop_state *old_colorop_state, *new_colorop_state; - int i; + struct drm_colorop_state *cstate; - for_each_oldnew_colorop_in_state(state, colorop, old_colorop_state, new_colorop_state, i) { - struct drm_colorop_state *cstate = use_old ? old_colorop_state : new_colorop_state; + if (drm_WARN_ON(plane->dev, !plane_state)) + return false; - if (cstate->colorop->plane != plane) - continue; + /* + * A commit may change only some colorops of a pipeline, and only those + * have old and new states here. Telling whether the pipeline modifies + * pixels requires every colorop of the selected pipeline, so fall back + * to the committed state of the untouched ones; it's both their old + * and new state. + */ + drm_for_each_colorop_in_pipeline(colorop, plane_state->color_pipeline) { + cstate = use_old ? + drm_atomic_get_old_colorop_state(state, colorop) : + drm_atomic_get_new_colorop_state(state, colorop); + + if (!cstate) + cstate = colorop->state; if (!cstate->bypass) return true; } + return false; } -- 2.53.0
