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
