From: James Lin <[email protected]>

[Why & How]
Cache the last programmed dc_flip_addrs/dc_plane_info/dc_scaling_info in
dm_plane_state and carry them across atomic_duplicate_state. In
amdgpu_dm_commit_planes() attach each flip_addr/plane_info/scaling_info
surface update only when it differs from the cache (memcmp), so an
address-only flip sends no plane_info/scaling_info update and stays on the
FAMS2 offload path.

Reviewed-by: Leo Li <[email protected]>
Signed-off-by: James Lin <[email protected]>
Signed-off-by: Chenyu Chen <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 43 ++++++++++++++++---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 14 ++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 32 ++++++++++++++
 .../amdgpu_dm/tests/amdgpu_dm_plane_test.c    | 21 ++++++++-
 4 files changed, 101 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 3ed0d8014d21..9c7fdd2844e5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3923,6 +3923,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_commit *state,
                bool plane_needs_flip;
                struct dc_plane_state *dc_plane;
                struct dm_plane_state *dm_new_plane_state = 
to_dm_plane_state(new_plane_state);
+               struct dm_plane_state *dm_old_plane_state = 
to_dm_plane_state(old_plane_state);
 
                /* Cursor plane is handled after stream updates */
                if (plane->type == DRM_PLANE_TYPE_CURSOR &&
@@ -3957,11 +3958,22 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_commit *state,
                        bundle->surface_updates[planes_count].cm = 
&dc_plane->cm;
                }
 
-               amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
-                                    &bundle->scaling_infos[planes_count]);
+               if (amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, 
new_plane_state,
+                                                        
&bundle->scaling_infos[planes_count])) {
+                       planes_count += 1;
+                       continue;
+               }
 
-               bundle->surface_updates[planes_count].scaling_info =
-                       &bundle->scaling_infos[planes_count];
+               /* Cache the newly computed scaling_info in the plane state */
+               *dm_new_plane_state->scaling_info =
+                       bundle->scaling_infos[planes_count];
+
+               /* Only send a scaling_info update if it changed vs the old 
state */
+               if (memcmp(dm_old_plane_state->scaling_info,
+                          dm_new_plane_state->scaling_info,
+                          sizeof(struct dc_scaling_info)))
+                       bundle->surface_updates[planes_count].scaling_info =
+                               &bundle->scaling_infos[planes_count];
 
                plane_needs_flip = old_plane_state->fb && new_plane_state->fb;
 
@@ -3982,8 +3994,16 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_commit *state,
                                 new_plane_state->plane->index,
                                 bundle->plane_infos[planes_count].dcc.enable);
 
-               bundle->surface_updates[planes_count].plane_info =
-                       &bundle->plane_infos[planes_count];
+               /* Cache the newly computed plane_info in the plane state */
+               *dm_new_plane_state->plane_info =
+                       bundle->plane_infos[planes_count];
+
+               /* Only send a plane_info update if it changed vs the old state 
*/
+               if (memcmp(dm_old_plane_state->plane_info,
+                          dm_new_plane_state->plane_info,
+                          sizeof(struct dc_plane_info)))
+                       bundle->surface_updates[planes_count].plane_info =
+                               &bundle->plane_infos[planes_count];
 
                if (acrtc_state->stream->link->psr_settings.psr_feature_enabled 
||
                    
acrtc_state->stream->link->replay_settings.replay_feature_enabled) {
@@ -4038,7 +4058,16 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_commit *state,
 
                timestamp_ns = ktime_get_ns();
                bundle->flip_addrs[planes_count].flip_timestamp_in_us = 
div_u64(timestamp_ns, 1000);
-               bundle->surface_updates[planes_count].flip_addr = 
&bundle->flip_addrs[planes_count];
+               /* Cache the newly computed flip_addr in the plane state */
+               *dm_new_plane_state->flip_addr =
+                       bundle->flip_addrs[planes_count];
+
+               /* Only send a flip_addr update if it changed vs the old state 
*/
+               if (memcmp(dm_old_plane_state->flip_addr,
+                          dm_new_plane_state->flip_addr,
+                          sizeof(struct dc_flip_addrs)))
+                       bundle->surface_updates[planes_count].flip_addr =
+                               &bundle->flip_addrs[planes_count];
                bundle->surface_updates[planes_count].surface = dc_plane;
 
                if (!bundle->surface_updates[planes_count].surface) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index c99a84bb040e..d2b1a63c99a5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -937,6 +937,10 @@ enum amdgpu_transfer_function {
        AMDGPU_TRANSFER_FUNCTION_COUNT
 };
 
+struct dc_flip_addrs;
+struct dc_scaling_info;
+struct dc_plane_info;
+
 struct dm_plane_state {
        struct drm_plane_state base;
        struct dc_plane_state *dc_state;
@@ -1006,6 +1010,16 @@ struct dm_plane_state {
         * applying blend LUT.
         */
        enum amdgpu_transfer_function blend_tf;
+
+       /* Cached per-plane surface descriptors kept in the DRM plane state.
+        * The DRM atomic old/new state swap lets us compare the previous
+        * commit's values (old) against the newly computed ones to detect a
+        * real plane change (vs an address-only flip) so DC only gets a
+        * scaling_info/plane_info surface update when it actually changed.
+        */
+       struct dc_flip_addrs *flip_addr;
+       struct dc_scaling_info *scaling_info;
+       struct dc_plane_info *plane_info;
 };
 
 enum amdgpu_dm_cursor_mode {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 23054952a6f6..7f85ef395013 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -33,6 +33,7 @@
 #include <drm/drm_fourcc.h>
 
 #include "amdgpu.h"
+#include "dc.h"
 #include "dal_asic_id.h"
 #include "amdgpu_display.h"
 #include "amdgpu_dm_trace.h"
@@ -1806,6 +1807,18 @@ STATIC_IFN_KUNIT void 
amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
        if (!amdgpu_state)
                return;
 
+       amdgpu_state->flip_addr = kzalloc_obj(*amdgpu_state->flip_addr);
+       amdgpu_state->scaling_info = kzalloc_obj(*amdgpu_state->scaling_info);
+       amdgpu_state->plane_info = kzalloc_obj(*amdgpu_state->plane_info);
+       if (!amdgpu_state->flip_addr || !amdgpu_state->scaling_info ||
+           !amdgpu_state->plane_info) {
+               kfree(amdgpu_state->flip_addr);
+               kfree(amdgpu_state->scaling_info);
+               kfree(amdgpu_state->plane_info);
+               kfree(amdgpu_state);
+               return;
+       }
+
        if (plane->state)
                plane->funcs->atomic_destroy_state(plane, plane->state);
 
@@ -1827,6 +1840,21 @@ amdgpu_dm_plane_drm_plane_duplicate_state(struct 
drm_plane *plane)
        if (!dm_plane_state)
                return NULL;
 
+       dm_plane_state->flip_addr = kmemdup(old_dm_plane_state->flip_addr,
+               sizeof(*old_dm_plane_state->flip_addr), GFP_KERNEL);
+       dm_plane_state->scaling_info = kmemdup(old_dm_plane_state->scaling_info,
+               sizeof(*old_dm_plane_state->scaling_info), GFP_KERNEL);
+       dm_plane_state->plane_info = kmemdup(old_dm_plane_state->plane_info,
+               sizeof(*old_dm_plane_state->plane_info), GFP_KERNEL);
+       if (!dm_plane_state->flip_addr || !dm_plane_state->scaling_info ||
+           !dm_plane_state->plane_info) {
+               kfree(dm_plane_state->flip_addr);
+               kfree(dm_plane_state->scaling_info);
+               kfree(dm_plane_state->plane_info);
+               kfree(dm_plane_state);
+               return NULL;
+       }
+
        __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
 
        if (old_dm_plane_state->dc_state) {
@@ -1946,6 +1974,10 @@ STATIC_IFN_KUNIT void 
amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *
        if (dm_plane_state->blend_lut)
                drm_property_blob_put(dm_plane_state->blend_lut);
 
+       kfree(dm_plane_state->flip_addr);
+       kfree(dm_plane_state->scaling_info);
+       kfree(dm_plane_state->plane_info);
+
        if (dm_plane_state->dc_state)
                dc_plane_state_release(dm_plane_state->dc_state);
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index a39c0acad6f7..9f9d99e1b47a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -2977,7 +2977,7 @@ static void dm_test_plane_reset_initializes_state(struct 
kunit *test)
        KUNIT_EXPECT_EQ(test, new_state->shaper_tf, 
AMDGPU_TRANSFER_FUNCTION_DEFAULT);
        KUNIT_EXPECT_EQ(test, new_state->blend_tf, 
AMDGPU_TRANSFER_FUNCTION_DEFAULT);
 
-       kfree(new_state);
+       amdgpu_dm_plane_drm_plane_destroy_state(plane, &new_state->base);
 }
 
 /**
@@ -3000,6 +3000,14 @@ static void 
dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
        KUNIT_ASSERT_NOT_NULL(test, plane);
        KUNIT_ASSERT_NOT_NULL(test, old_state);
 
+       /* duplicate_state kmemdup()s these, so the source state must own them. 
*/
+       old_state->flip_addr = kunit_kzalloc(test, 
sizeof(*old_state->flip_addr), GFP_KERNEL);
+       old_state->scaling_info = kunit_kzalloc(test, 
sizeof(*old_state->scaling_info), GFP_KERNEL);
+       old_state->plane_info = kunit_kzalloc(test, 
sizeof(*old_state->plane_info), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
        old_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_PQ_EOTF;
        old_state->hdr_mult = 0x123456789ULL;
        old_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_IDENTITY;
@@ -3016,7 +3024,7 @@ static void 
dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
        KUNIT_EXPECT_EQ(test, dup_state->blend_tf, 
AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF);
        KUNIT_EXPECT_NULL(test, dup_state->dc_state);
 
-       kfree(dup_state);
+       amdgpu_dm_plane_drm_plane_destroy_state(plane, dup_base);
 }
 
 /*
@@ -3067,6 +3075,15 @@ static void 
dm_test_plane_duplicate_state_copies_resources(struct kunit *test)
        kref_init(&dc_plane_state->refcount);
        old_state->dc_state = dc_plane_state;
        dm_test_attach_color_blobs(test, &adev->ddev, old_state);
+
+       /* duplicate_state kmemdup()s these, so the source state must own them. 
*/
+       old_state->flip_addr = kunit_kzalloc(test, 
sizeof(*old_state->flip_addr), GFP_KERNEL);
+       old_state->scaling_info = kunit_kzalloc(test, 
sizeof(*old_state->scaling_info), GFP_KERNEL);
+       old_state->plane_info = kunit_kzalloc(test, 
sizeof(*old_state->plane_info), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+       KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
        plane->state = &old_state->base;
 
        dup_base = amdgpu_dm_plane_drm_plane_duplicate_state(plane);
-- 
2.43.0

Reply via email to