Hi,

This change reintroduce some glitches/screen corruption on DCN321 with gamescope and a 4k@120Hz display, when transitioning from multiple planes (primary + overlay, and pipe split) to single plane (no pipe split). We see small white artifacts near the cursor in its first appearance on the screen after boot, and eventually a corrupted,colorful strip appears in "fast" transitions between single plane -> multi-plane -> single plane, for example, when moving the cursor (single plane), click on the Steam menu (multi planes) and moving the cursor just after (single plane).

The problem was previously solved by commit 24ddca9a3af1 ("drm/amd/display: Defer transitions from minimal state to final state") [1] and reintroduced again by this patch here, i.e., I don't see the issue if I revert this commit here in current asdn.
Also, the issue isn't reproducible if you disable SubVP.

[1] https://gitlab.freedesktop.org/agd5f/linux/-/commit/24ddca9a3af1

Best Regards,

Melissa

On 16/12/2025 06:56, Chenyu Chen wrote:
From: Dominik Kaszewski <[email protected]>

[Why]
Reenable new split implementation, previously partially reverted due
to issues with ODM on high-bandwidth displays 4k144Hz, resulting
in a corrupted gray screen.

Minimal flows require two separate commits, with extra intermediate
commit to enable seamless transitions, each followed by a swap. Since
new design requires commit to be run in execute and swap in cleanup
stage, an attempt was made to reorder them from CSCS (Commit-Swap-Commit-Swap)
to CCSS (Commit-Commit-Swap-Swap). Not only is this not viable, but
was implemented incorrectly as CCS, one swap missing.

[How]
* Change UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW/CURRENT to execute
and cleanup one commit, then run UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS,
which closely matches old implementation where minimal flows fall back
to seamless.
* Fix uninitialized variable error.

Reviewed-by: Nicholas Kazlauskas <[email protected]>
Signed-off-by: Dominik Kaszewski <[email protected]>
Signed-off-by: Chenyu Chen <[email protected]>
---
  drivers/gpu/drm/amd/display/dc/core/dc.c | 80 ++++++++++++------------
  1 file changed, 39 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 1be5c1c15798..57f6a4c8afff 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -784,7 +784,7 @@ bool dc_stream_get_crc(struct dc *dc, struct 
dc_stream_state *stream, uint8_t id
                       uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
  {
        int i;
-       struct pipe_ctx *pipe;
+       struct pipe_ctx *pipe = NULL;
        struct timing_generator *tg;
dc_exit_ips_for_hw_access(dc);
@@ -5437,35 +5437,23 @@ bool dc_update_planes_and_stream(struct dc *dc,
                struct dc_stream_state *stream,
                struct dc_stream_update *stream_update)
  {
-       bool ret = false;
+       struct dc_update_scratch_space *scratch = 
dc_update_planes_and_stream_init(
+                       dc,
+                       srf_updates,
+                       surface_count,
+                       stream,
+                       stream_update
+       );
+       bool more = true;
- dc_exit_ips_for_hw_access(dc);
-       /*
-        * update planes and stream version 3 separates FULL and FAST updates
-        * to their own sequences. It aims to clean up frequent checks for
-        * update type resulting unnecessary branching in logic flow. It also
-        * adds a new commit minimal transition sequence, which detects the need
-        * for minimal transition based on the actual comparison of current and
-        * new states instead of "predicting" it based on per feature software
-        * policy.i.e could_mpcc_tree_change_for_active_pipes. The new commit
-        * minimal transition sequence is made universal to any power saving
-        * features that would use extra free pipes such as Dynamic ODM/MPC
-        * Combine, MPO or SubVp. Therefore there is no longer a need to
-        * specially handle compatibility problems with transitions among those
-        * features as they are now transparent to the new sequence.
-        */
-       if (dc->ctx->dce_version >= DCN_VERSION_4_01 || dc->ctx->dce_version == 
DCN_VERSION_3_2 ||
-                       dc->ctx->dce_version == DCN_VERSION_3_21)
-               ret = update_planes_and_stream_v3(dc, srf_updates,
-                               surface_count, stream, stream_update);
-       else
-               ret = update_planes_and_stream_v2(dc, srf_updates,
-                       surface_count, stream, stream_update);
-       if (ret && (dc->ctx->dce_version >= DCN_VERSION_3_2 ||
-               dc->ctx->dce_version == DCN_VERSION_3_01))
-               clear_update_flags(srf_updates, surface_count, stream);
+       while (more) {
+               if (!dc_update_planes_and_stream_prepare(scratch))
+                       return false;
- return ret;
+               dc_update_planes_and_stream_execute(scratch);
+               more = dc_update_planes_and_stream_cleanup(scratch);
+       }
+       return true;
  }
void dc_commit_updates_for_stream(struct dc *dc,
@@ -7241,7 +7229,7 @@ static bool update_planes_and_stream_cleanup_v2(
        return false;
  }
-static void update_planes_and_stream_cleanup_v3_intermediate(
+static void update_planes_and_stream_cleanup_v3_release_minimal(
                struct dc_update_scratch_space *scratch,
                bool backup
  );
@@ -7262,6 +7250,10 @@ static bool update_planes_and_stream_prepare_v3(
                struct dc_update_scratch_space *scratch
  )
  {
+       if (scratch->flow == UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS) {
+               return true;
+       }
+       ASSERT(scratch->flow == UPDATE_V3_FLOW_INVALID);
        dc_exit_ips_for_hw_access(scratch->dc);
if (!update_planes_and_stream_state(
@@ -7327,11 +7319,11 @@ static bool update_planes_and_stream_prepare_v3(
                        return true;
                }
- update_planes_and_stream_cleanup_v3_intermediate(scratch, false);
+               update_planes_and_stream_cleanup_v3_release_minimal(scratch, 
false);
        }
- restore_planes_and_stream_state(&scratch->dc->scratch.current_state, scratch->stream);
        scratch->backup_context = scratch->dc->current_state;
+       restore_planes_and_stream_state(&scratch->dc->scratch.current_state, 
scratch->stream);
        dc_state_retain(scratch->backup_context);
        scratch->intermediate_context = create_minimal_transition_state(
                        scratch->dc,
@@ -7347,7 +7339,7 @@ static bool update_planes_and_stream_prepare_v3(
                        return true;
                }
- update_planes_and_stream_cleanup_v3_intermediate(scratch, true);
+               update_planes_and_stream_cleanup_v3_release_minimal(scratch, 
true);
        }
scratch->flow = UPDATE_V3_FLOW_INVALID;
@@ -7398,12 +7390,10 @@ static void update_planes_and_stream_execute_v3(
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
                update_planes_and_stream_execute_v3_commit(scratch, false, 
true);
-               update_planes_and_stream_execute_v3_commit(scratch, false, 
false);
                break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
                update_planes_and_stream_execute_v3_commit(scratch, true, true);
-               update_planes_and_stream_execute_v3_commit(scratch, false, 
false);
                break;
case UPDATE_V3_FLOW_INVALID:
@@ -7419,7 +7409,7 @@ static void 
update_planes_and_stream_cleanup_v3_new_context(
        swap_and_release_current_context(scratch->dc, scratch->new_context, 
scratch->stream);
  }
-static void update_planes_and_stream_cleanup_v3_intermediate(
+static void update_planes_and_stream_cleanup_v3_release_minimal(
                struct dc_update_scratch_space *scratch,
                bool backup
  )
@@ -7432,6 +7422,16 @@ static void 
update_planes_and_stream_cleanup_v3_intermediate(
        );
  }
+static void update_planes_and_stream_cleanup_v3_intermediate(
+               struct dc_update_scratch_space *scratch,
+               bool backup
+)
+{
+       swap_and_release_current_context(scratch->dc, 
scratch->intermediate_context, scratch->stream);
+       dc_state_retain(scratch->dc->current_state);
+       update_planes_and_stream_cleanup_v3_release_minimal(scratch, backup);
+}
+
  static bool update_planes_and_stream_cleanup_v3(
                struct dc_update_scratch_space *scratch
  )
@@ -7448,17 +7448,15 @@ static bool update_planes_and_stream_cleanup_v3(
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
                update_planes_and_stream_cleanup_v3_intermediate(scratch, 
false);
-               update_planes_and_stream_cleanup_v3_new_context(scratch);
-               break;
+               scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
+               return true;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
-               swap_and_release_current_context(scratch->dc, 
scratch->intermediate_context, scratch->stream);
-               dc_state_retain(scratch->dc->current_state);
                update_planes_and_stream_cleanup_v3_intermediate(scratch, true);
                dc_state_release(scratch->backup_context);
                restore_planes_and_stream_state(&scratch->dc->scratch.new_state, 
scratch->stream);
-               update_planes_and_stream_cleanup_v3_new_context(scratch);
-               break;
+               scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
+               return true;
case UPDATE_V3_FLOW_INVALID:
        default:

Reply via email to