<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>