<div dir="ltr">I have been able to test it on sti driver.<div><br></div><div>Thanks to have done the effort to make zpos generic.</div><div><br><div>You can add my tested-by on this patch.</div></div><div><br></div><div>Benjamin</div></div><div class="gmail_extra"><br><div class="gmail_quote">2016-01-12 14:39 GMT+01:00 Marek Szyprowski <span dir="ltr"><<a href="mailto:m.szyprowski@samsung.com" target="_blank">m.szyprowski@samsung.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This patch adds support for generic plane's zpos property property with<br>
well-defined semantics:<br>
- added zpos properties to drm core and plane state structures<br>
- added helpers for normalizing zpos properties of given set of planes<br>
- well defined semantics: planes are sorted by zpos values and then plane<br>
  id value if zpos equals<br>
<br>
Normalized zpos values are calculated automatically when generic<br>
muttable zpos property has been initialized. Drivers can simply use<br>
plane_state->normalized_zpos in their atomic_check and/or plane_update<br>
callbacks without any additional calls to DRM core.<br>
<br>
Signed-off-by: Marek Szyprowski <<a href="mailto:m.szyprowski@samsung.com">m.szyprowski@samsung.com</a>><br>
---<br>
 Documentation/DocBook/gpu.tmpl      |  14 ++++-<br>
 drivers/gpu/drm/drm_atomic.c        |   4 ++<br>
 drivers/gpu/drm/drm_atomic_helper.c | 116 ++++++++++++++++++++++++++++++++++++<br>
 drivers/gpu/drm/drm_crtc.c          |  53 ++++++++++++++++<br>
 include/drm/drm_crtc.h              |  14 +++++<br>
 5 files changed, 199 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl<br>
index 6c6e81a9eaf4..f6b7236141b6 100644<br>
--- a/Documentation/DocBook/gpu.tmpl<br>
+++ b/Documentation/DocBook/gpu.tmpl<br>
@@ -2004,7 +2004,7 @@ void intel_crt_init(struct drm_device *dev)<br>
        <td valign="top" >Description/Restrictions</td><br>
        </tr><br>
        <tr><br>
-       <td rowspan="37" valign="top" >DRM</td><br>
+       <td rowspan="38" valign="top" >DRM</td><br>
        <td valign="top" >Generic</td><br>
        <td valign="top" >“rotation”</td><br>
        <td valign="top" >BITMASK</td><br>
@@ -2256,7 +2256,7 @@ void intel_crt_init(struct drm_device *dev)<br>
        <td valign="top" >property to suggest an Y offset for a connector</td><br>
        </tr><br>
        <tr><br>
-       <td rowspan="3" valign="top" >Optional</td><br>
+       <td rowspan="4" valign="top" >Optional</td><br>
        <td valign="top" >“scaling mode”</td><br>
        <td valign="top" >ENUM</td><br>
        <td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td><br>
@@ -2280,6 +2280,16 @@ void intel_crt_init(struct drm_device *dev)<br>
        <td valign="top" >TBD</td><br>
        </tr><br>
        <tr><br>
+       <td valign="top" > "zpos" </td><br>
+       <td valign="top" >RANGE</td><br>
+       <td valign="top" >Min=0, Max=255</td><br>
+       <td valign="top" >Plane</td><br>
+       <td valign="top" >Plane's 'z' position during blending (0 for background, 255 for frontmost).<br>
+               If two planes assigned to same CRTC have equal zpos values, the plane with higher plane<br>
+               id is treated as closer to front. Can be IMMUTABLE if driver doesn't support changing<br>
+               planes' order.</td><br>
+       </tr><br>
+       <tr><br>
        <td rowspan="20" valign="top" >i915</td><br>
        <td rowspan="2" valign="top" >Generic</td><br>
        <td valign="top" >"Broadcast RGB"</td><br>
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c<br>
index 6a21e5c378c1..97bb069cb6a3 100644<br>
--- a/drivers/gpu/drm/drm_atomic.c<br>
+++ b/drivers/gpu/drm/drm_atomic.c<br>
@@ -614,6 +614,8 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,<br>
                state->src_h = val;<br>
        } else if (property == config->rotation_property) {<br>
                state->rotation = val;<br>
+       } else if (property == config->zpos_property) {<br>
+               state->zpos = val;<br>
        } else if (plane->funcs->atomic_set_property) {<br>
                return plane->funcs->atomic_set_property(plane, state,<br>
                                property, val);<br>
@@ -670,6 +672,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,<br>
                *val = state->src_h;<br>
        } else if (property == config->rotation_property) {<br>
                *val = state->rotation;<br>
+       } else if (property == config->zpos_property) {<br>
+               *val = state->zpos;<br>
        } else if (plane->funcs->atomic_get_property) {<br>
                return plane->funcs->atomic_get_property(plane, state, property, val);<br>
        } else {<br>
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c<br>
index d0d4b2ff7c21..257946fac94b 100644<br>
--- a/drivers/gpu/drm/drm_atomic_helper.c<br>
+++ b/drivers/gpu/drm/drm_atomic_helper.c<br>
@@ -31,6 +31,7 @@<br>
 #include <drm/drm_crtc_helper.h><br>
 #include <drm/drm_atomic_helper.h><br>
 #include <linux/fence.h><br>
+#include <linux/sort.h><br>
<br>
 /**<br>
  * DOC: overview<br>
@@ -507,6 +508,117 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,<br>
 }<br>
 EXPORT_SYMBOL(drm_atomic_helper_check_modeset);<br>
<br>
+static int drm_atomic_state_zpos_cmp(const void *a, const void *b)<br>
+{<br>
+       const struct drm_plane_state *sa = *(struct drm_plane_state **)a;<br>
+       const struct drm_plane_state *sb = *(struct drm_plane_state **)b;<br>
+       int zpos_a = (sa->zpos << 16) + sa->plane-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>;<br>
+       int zpos_b = (sb->zpos << 16) + sb->plane-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>;<br>
+<br>
+       return zpos_a - zpos_b;<br>
+}<br>
+<br>
+/**<br>
+ * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values<br>
+ * @crtc: crtc with planes, which have to be considered for normalization<br>
+ * @crtc_state: new atomic state to apply<br>
+ *<br>
+ * This function checks new states of all planes assigned to given crtc and<br>
+ * calculates normalized zpos value for them. Planes are compared first by their<br>
+ * zpos values, then by plane id (if zpos equals). Plane with lowest zpos value<br>
+ * is at the bottom. The plane_state->normalized_zpos is then filled with uniqe<br>
+ * values from 0 to number of active planes in crtc minus one.<br>
+ *<br>
+ * RETURNS<br>
+ * Zero for success or -errno<br>
+ */<br>
+int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,<br>
+                                             struct drm_crtc_state *crtc_state)<br>
+{<br>
+       struct drm_atomic_state *state = crtc_state->state;<br>
+       struct drm_device *dev = crtc->dev;<br>
+       int total_planes = dev->mode_config.num_total_plane;<br>
+       struct drm_plane_state **states;<br>
+       struct drm_plane *plane;<br>
+       int i, n = 0;<br>
+       int ret = 0;<br>
+<br>
+       DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",<br>
+                        crtc-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>, crtc->name);<br>
+<br>
+       states = kmalloc(total_planes * sizeof(*states), GFP_KERNEL);<br>
+       if (!states)<br>
+               return -ENOMEM;<br>
+<br>
+       /*<br>
+        * Normalization process might create new states for planes which<br>
+        * normalized_zpos has to be recalculated.<br>
+        */<br>
+       drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {<br>
+               struct drm_plane_state *plane_state =<br>
+                       drm_atomic_get_plane_state(state, plane);<br>
+               if (IS_ERR(plane_state)) {<br>
+                       ret = PTR_ERR(plane_state);<br>
+                       goto fail;<br>
+               }<br>
+               states[n++] = plane_state;<br>
+               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n",<br>
+                                plane-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>, plane->name, plane_state->zpos);<br>
+       }<br>
+<br>
+       sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL);<br>
+<br>
+       for (i = 0; i < n; i++) {<br>
+               plane = states[i]->plane;<br>
+               states[i]->normalized_zpos = i;<br>
+               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n",<br>
+                                plane-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>, plane->name, i);<br>
+       }<br>
+fail:<br>
+       kfree(states);<br>
+       return ret;<br>
+}<br>
+EXPORT_SYMBOL(drm_atomic_helper_crtc_normalize_zpos);<br>
+<br>
+static int drm_atomic_helper_normalize_zpos(struct drm_device *dev,<br>
+                                           struct drm_atomic_state *state)<br>
+{<br>
+       struct drm_crtc *crtc;<br>
+       struct drm_crtc_state *crtc_state;<br>
+       struct drm_plane *plane;<br>
+       struct drm_plane_state *plane_state;<br>
+       int i, ret = 0;<br>
+<br>
+       /*<br>
+        * If zpos_property is not initialized, then it makes no sense<br>
+        * to calculate normalized zpos values.<br>
+        */<br>
+       if (!dev->mode_config.zpos_property)<br>
+               return 0;<br>
+<br>
+       for_each_plane_in_state(state, plane, plane_state, i) {<br>
+               crtc = plane_state->crtc;<br>
+               if (!crtc)<br>
+                       continue;<br>
+               if (plane->state->zpos != plane_state->zpos) {<br>
+                       crtc_state =<br>
+                               drm_atomic_get_existing_crtc_state(state, crtc);<br>
+                       crtc_state->zpos_changed = true;<br>
+               }<br>
+       }<br>
+<br>
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {<br>
+               if (crtc_state->plane_mask != crtc->state->plane_mask ||<br>
+                   crtc_state->zpos_changed) {<br>
+                       ret = drm_atomic_helper_crtc_normalize_zpos(crtc,<br>
+                                                                   crtc_state);<br>
+                       if (ret)<br>
+                               return ret;<br>
+               }<br>
+       }<br>
+       return 0;<br>
+}<br>
+<br>
 /**<br>
  * drm_atomic_helper_check_planes - validate state object for planes changes<br>
  * @dev: DRM device<br>
@@ -532,6 +644,10 @@ drm_atomic_helper_check_planes(struct drm_device *dev,<br>
        struct drm_plane_state *plane_state;<br>
        int i, ret = 0;<br>
<br>
+       ret = drm_atomic_helper_normalize_zpos(dev, state);<br>
+       if (ret)<br>
+               return ret;<br>
+<br>
        for_each_plane_in_state(state, plane, plane_state, i) {<br>
                const struct drm_plane_helper_funcs *funcs;<br>
<br>
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c<br>
index 62fa95fa5471..54a21e7c1ca5 100644<br>
--- a/drivers/gpu/drm/drm_crtc.c<br>
+++ b/drivers/gpu/drm/drm_crtc.c<br>
@@ -5880,6 +5880,59 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,<br>
 EXPORT_SYMBOL(drm_mode_create_rotation_property);<br>
<br>
 /**<br>
+ * drm_mode_create_zpos_property - create muttable zpos property<br>
+ * @dev: DRM device<br>
+ *<br>
+ * This function initializes generic muttable zpos property and enables support<br>
+ * for it in drm core. Drivers can then attach this property to planes to enable<br>
+ * support for configurable planes arrangement during blending operation.<br>
+ * Drivers can also use drm_atomic_helper_normalize_zpos() function to calculate<br>
+ * drm_plane_state->normalized_zpos values.<br>
+ *<br>
+ * Returns:<br>
+ * Zero on success, negative errno on failure.<br>
+ */<br>
+int drm_mode_create_zpos_property(struct drm_device *dev)<br>
+{<br>
+       struct drm_property *prop;<br>
+<br>
+       prop = drm_property_create_range(dev, 0, "zpos", 0, 255);<br>
+       if (!prop)<br>
+               return -ENOMEM;<br>
+<br>
+       dev->mode_config.zpos_property = prop;<br>
+       return 0;<br>
+}<br>
+EXPORT_SYMBOL(drm_mode_create_zpos_property);<br>
+<br>
+/**<br>
+ * drm_plane_create_zpos_property - create immuttable zpos property<br>
+ * @dev: DRM device<br>
+ *<br>
+ * This function initializes generic immuttable zpos property and enables<br>
+ * support for it in drm core. Using this property driver lets userspace<br>
+ * to get the arrangement of the planes for blending operation and notifies<br>
+ * it that the hardware (or driver) doesn't support changing of the planes'<br>
+ * order.<br>
+ *<br>
+ * Returns:<br>
+ * Zero on success, negative errno on failure.<br>
+ */<br>
+int drm_mode_create_zpos_immutable_property(struct drm_device *dev)<br>
+{<br>
+       struct drm_property *prop;<br>
+<br>
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "zpos",<br>
+                                        0, 255);<br>
+       if (!prop)<br>
+               return -ENOMEM;<br>
+<br>
+       dev->mode_config.zpos_immutable_property = prop;<br>
+       return 0;<br>
+}<br>
+EXPORT_SYMBOL(drm_mode_create_zpos_immutable_property);<br>
+<br>
+/**<br>
  * DOC: Tile group<br>
  *<br>
  * Tile groups are used to represent tiled monitors with a unique<br>
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h<br>
index 3b040b355472..0607ad2ce918 100644<br>
--- a/include/drm/drm_crtc.h<br>
+++ b/include/drm/drm_crtc.h<br>
@@ -305,6 +305,7 @@ struct drm_plane_helper_funcs;<br>
  * @mode_changed: crtc_state->mode or crtc_state->enable has been changed<br>
  * @active_changed: crtc_state->active has been toggled.<br>
  * @connectors_changed: connectors to this crtc have been updated<br>
+ * @zpos_changed: zpos values of planes on this crtc have been updated<br>
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes<br>
  * @last_vblank_count: for helpers and drivers to capture the vblank of the<br>
  *     update to ensure framebuffer cleanup isn't done too early<br>
@@ -331,6 +332,7 @@ struct drm_crtc_state {<br>
        bool mode_changed : 1;<br>
        bool active_changed : 1;<br>
        bool connectors_changed : 1;<br>
+       bool zpos_changed : 1;<br>
<br>
        /* attached planes bitmask:<br>
         * WARNING: transitional helpers do not maintain plane_mask so<br>
@@ -1243,6 +1245,9 @@ struct drm_connector {<br>
  *     plane (in 16.16)<br>
  * @src_w: width of visible portion of plane (in 16.16)<br>
  * @src_h: height of visible portion of plane (in 16.16)<br>
+ * @zpos: priority of the given plane on crtc (optional)<br>
+ * @normalized_zpos: normalized value of zpos: uniqe, range from 0 to<br>
+ *     (number of planes - 1) for given crtc<br>
  * @state: backpointer to global drm_atomic_state<br>
  */<br>
 struct drm_plane_state {<br>
@@ -1263,6 +1268,10 @@ struct drm_plane_state {<br>
        /* Plane rotation */<br>
        unsigned int rotation;<br>
<br>
+       /* Plane zpos */<br>
+       unsigned int zpos;<br>
+       unsigned int normalized_zpos;<br>
+<br>
        struct drm_atomic_state *state;<br>
 };<br>
<br>
@@ -2083,6 +2092,8 @@ struct drm_mode_config {<br>
        struct drm_property *tile_property;<br>
        struct drm_property *plane_type_property;<br>
        struct drm_property *rotation_property;<br>
+       struct drm_property *zpos_property;<br>
+       struct drm_property *zpos_immutable_property;<br>
        struct drm_property *prop_src_x;<br>
        struct drm_property *prop_src_y;<br>
        struct drm_property *prop_src_w;<br>
@@ -2484,6 +2495,9 @@ extern struct drm_property *drm_mode_create_rotation_property(struct drm_device<br>
 extern unsigned int drm_rotation_simplify(unsigned int rotation,<br>
                                          unsigned int supported_rotations);<br>
<br>
+extern int drm_mode_create_zpos_property(struct drm_device *dev);<br>
+extern int drm_mode_create_zpos_immutable_property(struct drm_device *dev);<br>
+<br>
 /* Helpers */<br>
<br>
 static inline struct drm_plane *drm_plane_find(struct drm_device *dev,<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.2<br>
<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><span style="border-collapse:collapse;font-family:arial,sans-serif;font-size:13px"><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">Benjamin Gaignard </p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">Graphic Working Group</p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><span lang="EN-US" style="font-size:10pt;color:rgb(0,176,80)"><span style="color:rgb(0,68,252)"><a href="http://www.linaro.org/" style="color:rgb(0,0,204)" target="_blank">Linaro.org</a></span><b> </b></span><b><span lang="EN-US" style="font-size:10pt">│ </span></b><span lang="EN-US" style="font-size:10pt">Open source software for ARM SoCs</span></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><u></u></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><span lang="EN-US" style="font-size:10pt">Follow <b>Linaro: </b></span><span style="font-size:10pt;color:rgb(0,68,252)"><a href="http://www.facebook.com/pages/Linaro" style="color:rgb(0,0,204)" target="_blank"><span style="color:blue">Facebook</span></a></span><span style="font-size:10pt"> | <span style="color:rgb(0,68,252)"><a href="http://twitter.com/#!/linaroorg" style="color:rgb(0,0,204)" target="_blank"><span style="color:blue">Twitter</span></a></span> | <span style="color:rgb(0,68,252)"><a href="http://www.linaro.org/linaro-blog/" style="color:rgb(0,0,204)" target="_blank"><span style="color:blue">Blog</span></a></span></span></p></span></div>
</div>