From: Leo Li <sunpeng.li@xxxxxxx> [Why] Compositors have different ways of assigning surfaces to DRM planes for render offloading. It may decide between various strategies: overlay, underlay, or a mix of both (see here for more info: https://gitlab.freedesktop.org/emersion/libliftoff/-/issues/76) One way for compositors to implement the underlay strategy is to assign a higher zpos to the DRM_PRIMARY plane than the DRM_OVERLAY planes, effectively turning the DRM_OVERLAY plane into an underlay plane. Today, amdgpu attaches an immutable zpos of 0 to the DRM_PRIMARY plane. This however, is an arbitrary restriction. DCN pipes are general purpose, and can be arranged in any z-order. To support compositors using this allocation scheme, we can set a non-zero immutable zpos for the PRIMARY, allowing the placement of OVERLAYS (mutable zpos range 0-254) beneath the PRIMARY. [How] Assign a zpos = #no of OVERLAY planes to the PRIMARY plane. Then, clean up any assumptions in the driver of PRIMARY plane having the lowest zpos. Signed-off-by: Leo Li <sunpeng.li@xxxxxxx> Reviewed-by: Harry Wentland <harry.wentland@xxxxxxx> Acked-by: Pekka Paalanen <pekka.paalanen@xxxxxxxxxxxxx> v2: Fix typo s/decending/descending/ --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 34 +++++++++++++++++-- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 18 +++++++--- 2 files changed, 44 insertions(+), 8 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 b4b5b73707c1..6782ca1137d4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -80,6 +80,7 @@ #include <linux/firmware.h> #include <linux/component.h> #include <linux/dmi.h> +#include <linux/sort.h> #include <drm/display/drm_dp_mst_helper.h> #include <drm/display/drm_hdmi_helper.h> @@ -375,6 +376,20 @@ static inline void reverse_planes_order(struct dc_surface_update *array_of_surfa swap(array_of_surface_update[i], array_of_surface_update[j]); } +/* + * DC will program planes with their z-order determined by their ordering + * in the dc_surface_updates array. This comparator is used to sort them + * by descending zpos. + */ +static int dm_plane_layer_index_cmp(const void *a, const void *b) +{ + const struct dc_surface_update *sa = (struct dc_surface_update *)a; + const struct dc_surface_update *sb = (struct dc_surface_update *)b; + + /* Sort by descending dc_plane layer_index (i.e. normalized_zpos) */ + return sb->surface->layer_index - sa->surface->layer_index; +} + /** * update_planes_and_stream_adapter() - Send planes to be updated in DC * @@ -399,7 +414,8 @@ static inline bool update_planes_and_stream_adapter(struct dc *dc, struct dc_stream_update *stream_update, struct dc_surface_update *array_of_surface_update) { - reverse_planes_order(array_of_surface_update, planes_count); + sort(array_of_surface_update, planes_count, + sizeof(*array_of_surface_update), dm_plane_layer_index_cmp, NULL); /* * Previous frame finished and HW is ready for optimization. @@ -9503,6 +9519,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) for (j = 0; j < status->plane_count; j++) dummy_updates[j].surface = status->plane_states[0]; + sort(dummy_updates, status->plane_count, + sizeof(*dummy_updates), dm_plane_layer_index_cmp, NULL); mutex_lock(&dm->dc_lock); dc_update_planes_and_stream(dm->dc, @@ -10237,6 +10255,16 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (new_crtc_state->color_mgmt_changed) return true; + /* + * On zpos change, planes need to be reordered by removing and re-adding + * them one by one to the dc state, in order of descending zpos. + * + * TODO: We can likely skip bandwidth validation if the only thing that + * changed about the plane was it'z z-ordering. + */ + if (new_crtc_state->zpos_changed) + return true; + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) return true; @@ -11076,7 +11104,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } /* Remove exiting planes if they are modified */ - for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { + for_each_oldnew_plane_in_descending_zpos(state, plane, old_plane_state, new_plane_state) { if (old_plane_state->fb && new_plane_state->fb && get_mem_type(old_plane_state->fb) != get_mem_type(new_plane_state->fb)) @@ -11121,7 +11149,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } /* Add new/modified planes */ - for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { + for_each_oldnew_plane_in_descending_zpos(state, plane, old_plane_state, new_plane_state) { ret = dm_update_plane_state(dc, state, plane, old_plane_state, new_plane_state, 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 3e467244ad07..bb534b2b0b71 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 @@ -104,8 +104,6 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state *global_alpha = false; *global_alpha_value = 0xff; - if (plane_state->plane->type == DRM_PLANE_TYPE_PRIMARY) - return; if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI || plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) { @@ -1701,6 +1699,7 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, int res = -EPERM; unsigned int supported_rotations; uint64_t *modifiers = NULL; + unsigned int primary_zpos = dm->dc->caps.max_slave_planes; num_formats = amdgpu_dm_plane_get_plane_formats(plane, plane_cap, formats, ARRAY_SIZE(formats)); @@ -1730,10 +1729,19 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, } if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - drm_plane_create_zpos_immutable_property(plane, 0); + /* + * Allow OVERLAY planes to be used as underlays by assigning an + * immutable zpos = # of OVERLAY planes to the PRIMARY plane. + */ + drm_plane_create_zpos_immutable_property(plane, primary_zpos); } else if (plane->type == DRM_PLANE_TYPE_OVERLAY) { - unsigned int zpos = 1 + drm_plane_index(plane); - drm_plane_create_zpos_property(plane, zpos, 1, 254); + /* + * OVERLAY planes can be below or above the PRIMARY, but cannot + * be above the CURSOR plane. + */ + unsigned int zpos = primary_zpos + 1 + drm_plane_index(plane); + + drm_plane_create_zpos_property(plane, zpos, 0, 254); } else if (plane->type == DRM_PLANE_TYPE_CURSOR) { drm_plane_create_zpos_immutable_property(plane, 255); } -- 2.44.0