aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ser <[email protected]>2021-10-06 14:06:05 +0000
committerAlex Deucher <[email protected]>2021-10-13 14:14:34 -0400
commitd1bfbe8a3202640c28a5769faff49b732af2438b (patch)
tree87ef2019c497c1cd13b544ac00a4b7bf28883a63
parent7e3fb209d518112628f3f5abd6e66053ac4b0767 (diff)
amd/display: check cursor plane matches underlying plane
The current logic checks whether the cursor plane blending properties match the primary plane's. However that's wrong, because the cursor is painted on all planes underneath. If the cursor is over the primary plane and the overlay plane, it's painted on both pipes. Iterate over the CRTC planes and check their scaling match the cursor's. v4: fix typo in commit message (Harry) Signed-off-by: Simon Ser <[email protected]> Cc: Alex Deucher <[email protected]> Cc: Harry Wentland <[email protected]> Cc: Nicholas Kazlauskas <[email protected]> Cc: Bas Nieuwenhuizen <[email protected]> Cc: Rodrigo Siqueira <[email protected]> Cc: Sean Paul <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c49
1 files changed, 34 insertions, 15 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 f35561b5a465..ec914823ec6f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10535,18 +10535,18 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
struct drm_crtc *crtc,
struct drm_crtc_state *new_crtc_state)
{
- struct drm_plane_state *new_cursor_state, *new_primary_state;
- int cursor_scale_w, cursor_scale_h, primary_scale_w, primary_scale_h;
+ struct drm_plane *cursor = crtc->cursor, *underlying;
+ struct drm_plane_state *new_cursor_state, *new_underlying_state;
+ int i;
+ int cursor_scale_w, cursor_scale_h, underlying_scale_w, underlying_scale_h;
/* On DCE and DCN there is no dedicated hardware cursor plane. We get a
* cursor per pipe but it's going to inherit the scaling and
* positioning from the underlying pipe. Check the cursor plane's
- * blending properties match the primary plane's. */
+ * blending properties match the underlying planes'. */
- new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor);
- new_primary_state = drm_atomic_get_new_plane_state(state, crtc->primary);
- if (!new_cursor_state || !new_primary_state ||
- !new_cursor_state->fb || !new_primary_state->fb) {
+ new_cursor_state = drm_atomic_get_new_plane_state(state, cursor);
+ if (!new_cursor_state || !new_cursor_state->fb) {
return 0;
}
@@ -10555,15 +10555,34 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
cursor_scale_h = new_cursor_state->crtc_h * 1000 /
(new_cursor_state->src_h >> 16);
- primary_scale_w = new_primary_state->crtc_w * 1000 /
- (new_primary_state->src_w >> 16);
- primary_scale_h = new_primary_state->crtc_h * 1000 /
- (new_primary_state->src_h >> 16);
+ for_each_new_plane_in_state_reverse(state, underlying, new_underlying_state, i) {
+ /* Narrow down to non-cursor planes on the same CRTC as the cursor */
+ if (new_underlying_state->crtc != crtc || underlying == crtc->cursor)
+ continue;
- if (cursor_scale_w != primary_scale_w ||
- cursor_scale_h != primary_scale_h) {
- drm_dbg_atomic(crtc->dev, "Cursor plane scaling doesn't match primary plane\n");
- return -EINVAL;
+ /* Ignore disabled planes */
+ if (!new_underlying_state->fb)
+ continue;
+
+ underlying_scale_w = new_underlying_state->crtc_w * 1000 /
+ (new_underlying_state->src_w >> 16);
+ underlying_scale_h = new_underlying_state->crtc_h * 1000 /
+ (new_underlying_state->src_h >> 16);
+
+ if (cursor_scale_w != underlying_scale_w ||
+ cursor_scale_h != underlying_scale_h) {
+ drm_dbg_atomic(crtc->dev,
+ "Cursor [PLANE:%d:%s] scaling doesn't match underlying [PLANE:%d:%s]\n",
+ cursor->base.id, cursor->name, underlying->base.id, underlying->name);
+ return -EINVAL;
+ }
+
+ /* If this plane covers the whole CRTC, no need to check planes underneath */
+ if (new_underlying_state->crtc_x <= 0 &&
+ new_underlying_state->crtc_y <= 0 &&
+ new_underlying_state->crtc_x + new_underlying_state->crtc_w >= new_crtc_state->mode.hdisplay &&
+ new_underlying_state->crtc_y + new_underlying_state->crtc_h >= new_crtc_state->mode.vdisplay)
+ break;
}
return 0;