[AMD Official Use Only - AMD Internal Distribution Only]

Hi Melissa,

Thank you for letting me know, I will look into this regression.

Best regards,
Dominik Kaszewski
Senior Software Engineer
SW - Display NPI

-----Original Message-----
From: Melissa Wen <[email protected]>
Sent: Monday, January 12, 2026 12:44 PM
To: Chen, Chen-Yu <[email protected]>; [email protected]
Cc: Wentland, Harry <[email protected]>; Li, Sun peng (Leo) 
<[email protected]>; Pillai, Aurabindo <[email protected]>; Li, Roman 
<[email protected]>; Lin, Wayne <[email protected]>; Chung, ChiaHsuan (Tom) 
<[email protected]>; Zuo, Jerry <[email protected]>; Wheeler, Daniel 
<[email protected]>; Wu, Ray <[email protected]>; LIPSKI, IVAN 
<[email protected]>; Hung, Alex <[email protected]>; Kaszewski, Dominik 
<[email protected]>; Kazlauskas, Nicholas <[email protected]>
Subject: Re: [PATCH 06/16] drm/amd/display: Fix and reenable 
UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL



On 06/01/2026 09:18, Melissa Wen wrote:
> 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.

Just to reinforce that the situation I describe here affects this issue in a 
similar way:
- https://gitlab.freedesktop.org/drm/amd/-/issues/3614 ("[DCN32/7900XTX] when 
VRR is active + an overlay plane is in use, using a hardware cursor in 
gamescope-session causes artifacts during transition out of scan-out")

Melissa

>
> [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