From: Leo Li <sunpeng...@amd.com>

[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...@amd.com>
Reviewed-by: Harry Wentland <harry.wentl...@amd.com>
Acked-by: Pekka Paalanen <pekka.paala...@collabora.com>

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

Reply via email to