144d1240dSMarek Szyprowski /* 244d1240dSMarek Szyprowski * Copyright (C) 2016 Samsung Electronics Co.Ltd 344d1240dSMarek Szyprowski * Authors: 444d1240dSMarek Szyprowski * Marek Szyprowski <m.szyprowski@samsung.com> 544d1240dSMarek Szyprowski * 644d1240dSMarek Szyprowski * DRM core plane blending related functions 744d1240dSMarek Szyprowski * 844d1240dSMarek Szyprowski * Permission to use, copy, modify, distribute, and sell this software and its 944d1240dSMarek Szyprowski * documentation for any purpose is hereby granted without fee, provided that 1044d1240dSMarek Szyprowski * the above copyright notice appear in all copies and that both that copyright 1144d1240dSMarek Szyprowski * notice and this permission notice appear in supporting documentation, and 1244d1240dSMarek Szyprowski * that the name of the copyright holders not be used in advertising or 1344d1240dSMarek Szyprowski * publicity pertaining to distribution of the software without specific, 1444d1240dSMarek Szyprowski * written prior permission. The copyright holders make no representations 1544d1240dSMarek Szyprowski * about the suitability of this software for any purpose. It is provided "as 1644d1240dSMarek Szyprowski * is" without express or implied warranty. 1744d1240dSMarek Szyprowski * 1844d1240dSMarek Szyprowski * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1944d1240dSMarek Szyprowski * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 2044d1240dSMarek Szyprowski * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 2144d1240dSMarek Szyprowski * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 2244d1240dSMarek Szyprowski * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2344d1240dSMarek Szyprowski * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2444d1240dSMarek Szyprowski * OF THIS SOFTWARE. 2544d1240dSMarek Szyprowski */ 260500c04eSSam Ravnborg 2744d1240dSMarek Szyprowski #include <linux/export.h> 2844d1240dSMarek Szyprowski #include <linux/slab.h> 2944d1240dSMarek Szyprowski #include <linux/sort.h> 3044d1240dSMarek Szyprowski 310500c04eSSam Ravnborg #include <drm/drm_atomic.h> 320500c04eSSam Ravnborg #include <drm/drm_blend.h> 330500c04eSSam Ravnborg #include <drm/drm_device.h> 340500c04eSSam Ravnborg #include <drm/drm_print.h> 350500c04eSSam Ravnborg 36c30b4400SVille Syrjälä #include "drm_crtc_internal.h" 3744d1240dSMarek Szyprowski 381e4d84c6SDaniel Vetter /** 391e4d84c6SDaniel Vetter * DOC: overview 401e4d84c6SDaniel Vetter * 411e4d84c6SDaniel Vetter * The basic plane composition model supported by standard plane properties only 421e4d84c6SDaniel Vetter * has a source rectangle (in logical pixels within the &drm_framebuffer), with 431e4d84c6SDaniel Vetter * sub-pixel accuracy, which is scaled up to a pixel-aligned destination 441e4d84c6SDaniel Vetter * rectangle in the visible area of a &drm_crtc. The visible area of a CRTC is 451e4d84c6SDaniel Vetter * defined by the horizontal and vertical visible pixels (stored in @hdisplay 46d574528aSDaniel Vetter * and @vdisplay) of the requested mode (stored in &drm_crtc_state.mode). These 47d574528aSDaniel Vetter * two rectangles are both stored in the &drm_plane_state. 481e4d84c6SDaniel Vetter * 491e4d84c6SDaniel Vetter * For the atomic ioctl the following standard (atomic) properties on the plane object 501e4d84c6SDaniel Vetter * encode the basic plane composition model: 511e4d84c6SDaniel Vetter * 521e4d84c6SDaniel Vetter * SRC_X: 531e4d84c6SDaniel Vetter * X coordinate offset for the source rectangle within the 541e4d84c6SDaniel Vetter * &drm_framebuffer, in 16.16 fixed point. Must be positive. 551e4d84c6SDaniel Vetter * SRC_Y: 561e4d84c6SDaniel Vetter * Y coordinate offset for the source rectangle within the 571e4d84c6SDaniel Vetter * &drm_framebuffer, in 16.16 fixed point. Must be positive. 581e4d84c6SDaniel Vetter * SRC_W: 591e4d84c6SDaniel Vetter * Width for the source rectangle within the &drm_framebuffer, in 16.16 601e4d84c6SDaniel Vetter * fixed point. SRC_X plus SRC_W must be within the width of the source 611e4d84c6SDaniel Vetter * framebuffer. Must be positive. 621e4d84c6SDaniel Vetter * SRC_H: 631e4d84c6SDaniel Vetter * Height for the source rectangle within the &drm_framebuffer, in 16.16 641e4d84c6SDaniel Vetter * fixed point. SRC_Y plus SRC_H must be within the height of the source 651e4d84c6SDaniel Vetter * framebuffer. Must be positive. 661e4d84c6SDaniel Vetter * CRTC_X: 671e4d84c6SDaniel Vetter * X coordinate offset for the destination rectangle. Can be negative. 681e4d84c6SDaniel Vetter * CRTC_Y: 691e4d84c6SDaniel Vetter * Y coordinate offset for the destination rectangle. Can be negative. 701e4d84c6SDaniel Vetter * CRTC_W: 711e4d84c6SDaniel Vetter * Width for the destination rectangle. CRTC_X plus CRTC_W can extend past 721e4d84c6SDaniel Vetter * the currently visible horizontal area of the &drm_crtc. 731e4d84c6SDaniel Vetter * CRTC_H: 741e4d84c6SDaniel Vetter * Height for the destination rectangle. CRTC_Y plus CRTC_H can extend past 751e4d84c6SDaniel Vetter * the currently visible vertical area of the &drm_crtc. 761e4d84c6SDaniel Vetter * FB_ID: 771e4d84c6SDaniel Vetter * Mode object ID of the &drm_framebuffer this plane should scan out. 781e4d84c6SDaniel Vetter * CRTC_ID: 791e4d84c6SDaniel Vetter * Mode object ID of the &drm_crtc this plane should be connected to. 801e4d84c6SDaniel Vetter * 811e4d84c6SDaniel Vetter * Note that the source rectangle must fully lie within the bounds of the 821e4d84c6SDaniel Vetter * &drm_framebuffer. The destination rectangle can lie outside of the visible 831e4d84c6SDaniel Vetter * area of the current mode of the CRTC. It must be apprpriately clipped by the 841e4d84c6SDaniel Vetter * driver, which can be done by calling drm_plane_helper_check_update(). Drivers 851e4d84c6SDaniel Vetter * are also allowed to round the subpixel sampling positions appropriately, but 861e4d84c6SDaniel Vetter * only to the next full pixel. No pixel outside of the source rectangle may 871e4d84c6SDaniel Vetter * ever be sampled, which is important when applying more sophisticated 881e4d84c6SDaniel Vetter * filtering than just a bilinear one when scaling. The filtering mode when 891e4d84c6SDaniel Vetter * scaling is unspecified. 901e4d84c6SDaniel Vetter * 911e4d84c6SDaniel Vetter * On top of this basic transformation additional properties can be exposed by 921e4d84c6SDaniel Vetter * the driver: 931e4d84c6SDaniel Vetter * 94ae0e2826SMaxime Ripard * alpha: 95ae0e2826SMaxime Ripard * Alpha is setup with drm_plane_create_alpha_property(). It controls the 96ae0e2826SMaxime Ripard * plane-wide opacity, from transparent (0) to opaque (0xffff). It can be 97ae0e2826SMaxime Ripard * combined with pixel alpha. 98ae0e2826SMaxime Ripard * The pixel values in the framebuffers are expected to not be 99ae0e2826SMaxime Ripard * pre-multiplied by the global alpha associated to the plane. 100ae0e2826SMaxime Ripard * 1014d10bd45SDaniel Vetter * rotation: 1024d10bd45SDaniel Vetter * Rotation is set up with drm_plane_create_rotation_property(). It adds a 1031e4d84c6SDaniel Vetter * rotation and reflection step between the source and destination rectangles. 1041e4d84c6SDaniel Vetter * Without this property the rectangle is only scaled, but not rotated or 1051e4d84c6SDaniel Vetter * reflected. 1061e4d84c6SDaniel Vetter * 1071f86fa15SAlexandru Gheorghe * Possbile values: 1081f86fa15SAlexandru Gheorghe * 1091f86fa15SAlexandru Gheorghe * "rotate-<degrees>": 1101f86fa15SAlexandru Gheorghe * Signals that a drm plane is rotated <degrees> degrees in counter 1111f86fa15SAlexandru Gheorghe * clockwise direction. 1121f86fa15SAlexandru Gheorghe * 1131f86fa15SAlexandru Gheorghe * "reflect-<axis>": 1141f86fa15SAlexandru Gheorghe * Signals that the contents of a drm plane is reflected along the 1151f86fa15SAlexandru Gheorghe * <axis> axis, in the same way as mirroring. 1161f86fa15SAlexandru Gheorghe * 1171f86fa15SAlexandru Gheorghe * reflect-x:: 1181f86fa15SAlexandru Gheorghe * 1191f86fa15SAlexandru Gheorghe * |o | | o| 1201f86fa15SAlexandru Gheorghe * | | -> | | 1211f86fa15SAlexandru Gheorghe * | v| |v | 1221f86fa15SAlexandru Gheorghe * 1231f86fa15SAlexandru Gheorghe * reflect-y:: 1241f86fa15SAlexandru Gheorghe * 1251f86fa15SAlexandru Gheorghe * |o | | ^| 1261f86fa15SAlexandru Gheorghe * | | -> | | 1271f86fa15SAlexandru Gheorghe * | v| |o | 1281f86fa15SAlexandru Gheorghe * 1294d10bd45SDaniel Vetter * zpos: 1304d10bd45SDaniel Vetter * Z position is set up with drm_plane_create_zpos_immutable_property() and 1311e4d84c6SDaniel Vetter * drm_plane_create_zpos_property(). It controls the visibility of overlapping 1321e4d84c6SDaniel Vetter * planes. Without this property the primary plane is always below the cursor 1331e4d84c6SDaniel Vetter * plane, and ordering between all other planes is undefined. 1341e4d84c6SDaniel Vetter * 135a5ec8332SLowry Li * pixel blend mode: 136a5ec8332SLowry Li * Pixel blend mode is set up with drm_plane_create_blend_mode_property(). 137a5ec8332SLowry Li * It adds a blend mode for alpha blending equation selection, describing 138a5ec8332SLowry Li * how the pixels from the current plane are composited with the 139a5ec8332SLowry Li * background. 140a5ec8332SLowry Li * 141a5ec8332SLowry Li * Three alpha blending equations are defined: 142a5ec8332SLowry Li * 143a5ec8332SLowry Li * "None": 144a5ec8332SLowry Li * Blend formula that ignores the pixel alpha:: 145a5ec8332SLowry Li * 146a5ec8332SLowry Li * out.rgb = plane_alpha * fg.rgb + 147a5ec8332SLowry Li * (1 - plane_alpha) * bg.rgb 148a5ec8332SLowry Li * 149a5ec8332SLowry Li * "Pre-multiplied": 150a5ec8332SLowry Li * Blend formula that assumes the pixel color values 151a5ec8332SLowry Li * have been already pre-multiplied with the alpha 152a5ec8332SLowry Li * channel values:: 153a5ec8332SLowry Li * 154a5ec8332SLowry Li * out.rgb = plane_alpha * fg.rgb + 155a5ec8332SLowry Li * (1 - (plane_alpha * fg.alpha)) * bg.rgb 156a5ec8332SLowry Li * 157a5ec8332SLowry Li * "Coverage": 158a5ec8332SLowry Li * Blend formula that assumes the pixel color values have not 159a5ec8332SLowry Li * been pre-multiplied and will do so when blending them to the 160a5ec8332SLowry Li * background color values:: 161a5ec8332SLowry Li * 162a5ec8332SLowry Li * out.rgb = plane_alpha * fg.alpha * fg.rgb + 163a5ec8332SLowry Li * (1 - (plane_alpha * fg.alpha)) * bg.rgb 164a5ec8332SLowry Li * 165a5ec8332SLowry Li * Using the following symbols: 166a5ec8332SLowry Li * 167a5ec8332SLowry Li * "fg.rgb": 168a5ec8332SLowry Li * Each of the RGB component values from the plane's pixel 169a5ec8332SLowry Li * "fg.alpha": 170a5ec8332SLowry Li * Alpha component value from the plane's pixel. If the plane's 171a5ec8332SLowry Li * pixel format has no alpha component, then this is assumed to be 172a5ec8332SLowry Li * 1.0. In these cases, this property has no effect, as all three 173a5ec8332SLowry Li * equations become equivalent. 174a5ec8332SLowry Li * "bg.rgb": 175a5ec8332SLowry Li * Each of the RGB component values from the background 176a5ec8332SLowry Li * "plane_alpha": 177a5ec8332SLowry Li * Plane alpha value set by the plane "alpha" property. If the 178a5ec8332SLowry Li * plane does not expose the "alpha" property, then this is 179a5ec8332SLowry Li * assumed to be 1.0 180a5ec8332SLowry Li * 1811e4d84c6SDaniel Vetter * Note that all the property extensions described here apply either to the 1821e4d84c6SDaniel Vetter * plane or the CRTC (e.g. for the background color, which currently is not 1831e4d84c6SDaniel Vetter * exposed and assumed to be black). 1841e4d84c6SDaniel Vetter */ 1851e4d84c6SDaniel Vetter 1861e4d84c6SDaniel Vetter /** 187ae0e2826SMaxime Ripard * drm_plane_create_alpha_property - create a new alpha property 188ae0e2826SMaxime Ripard * @plane: drm plane 189ae0e2826SMaxime Ripard * 190ae0e2826SMaxime Ripard * This function creates a generic, mutable, alpha property and enables support 191ae0e2826SMaxime Ripard * for it in the DRM core. It is attached to @plane. 192ae0e2826SMaxime Ripard * 193ae0e2826SMaxime Ripard * The alpha property will be allowed to be within the bounds of 0 194ae0e2826SMaxime Ripard * (transparent) to 0xffff (opaque). 195ae0e2826SMaxime Ripard * 196ae0e2826SMaxime Ripard * Returns: 197ae0e2826SMaxime Ripard * 0 on success, negative error code on failure. 198ae0e2826SMaxime Ripard */ 199ae0e2826SMaxime Ripard int drm_plane_create_alpha_property(struct drm_plane *plane) 200ae0e2826SMaxime Ripard { 201ae0e2826SMaxime Ripard struct drm_property *prop; 202ae0e2826SMaxime Ripard 203ae0e2826SMaxime Ripard prop = drm_property_create_range(plane->dev, 0, "alpha", 204ae0e2826SMaxime Ripard 0, DRM_BLEND_ALPHA_OPAQUE); 205ae0e2826SMaxime Ripard if (!prop) 206ae0e2826SMaxime Ripard return -ENOMEM; 207ae0e2826SMaxime Ripard 208ae0e2826SMaxime Ripard drm_object_attach_property(&plane->base, prop, DRM_BLEND_ALPHA_OPAQUE); 209ae0e2826SMaxime Ripard plane->alpha_property = prop; 210ae0e2826SMaxime Ripard 211ae0e2826SMaxime Ripard if (plane->state) 212ae0e2826SMaxime Ripard plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE; 213ae0e2826SMaxime Ripard 214ae0e2826SMaxime Ripard return 0; 215ae0e2826SMaxime Ripard } 216ae0e2826SMaxime Ripard EXPORT_SYMBOL(drm_plane_create_alpha_property); 217ae0e2826SMaxime Ripard 218ae0e2826SMaxime Ripard /** 2196686df8cSVille Syrjälä * drm_plane_create_rotation_property - create a new rotation property 2206686df8cSVille Syrjälä * @plane: drm plane 2216686df8cSVille Syrjälä * @rotation: initial value of the rotation property 2221e4d84c6SDaniel Vetter * @supported_rotations: bitmask of supported rotations and reflections 2231e4d84c6SDaniel Vetter * 2241e4d84c6SDaniel Vetter * This creates a new property with the selected support for transformations. 2251e4d84c6SDaniel Vetter * 2261e4d84c6SDaniel Vetter * Since a rotation by 180° degress is the same as reflecting both along the x 2271e4d84c6SDaniel Vetter * and the y axis the rotation property is somewhat redundant. Drivers can use 2281e4d84c6SDaniel Vetter * drm_rotation_simplify() to normalize values of this property. 2291e4d84c6SDaniel Vetter * 2301e4d84c6SDaniel Vetter * The property exposed to userspace is a bitmask property (see 2311e4d84c6SDaniel Vetter * drm_property_create_bitmask()) called "rotation" and has the following 2321e4d84c6SDaniel Vetter * bitmask enumaration values: 2331e4d84c6SDaniel Vetter * 234c2c446adSRobert Foss * DRM_MODE_ROTATE_0: 2351e4d84c6SDaniel Vetter * "rotate-0" 236c2c446adSRobert Foss * DRM_MODE_ROTATE_90: 2371e4d84c6SDaniel Vetter * "rotate-90" 238c2c446adSRobert Foss * DRM_MODE_ROTATE_180: 2391e4d84c6SDaniel Vetter * "rotate-180" 240c2c446adSRobert Foss * DRM_MODE_ROTATE_270: 2411e4d84c6SDaniel Vetter * "rotate-270" 242c2c446adSRobert Foss * DRM_MODE_REFLECT_X: 2431e4d84c6SDaniel Vetter * "reflect-x" 244c2c446adSRobert Foss * DRM_MODE_REFLECT_Y: 2451e4d84c6SDaniel Vetter * "reflect-y" 2461e4d84c6SDaniel Vetter * 2471e4d84c6SDaniel Vetter * Rotation is the specified amount in degrees in counter clockwise direction, 2481e4d84c6SDaniel Vetter * the X and Y axis are within the source rectangle, i.e. the X/Y axis before 2491e4d84c6SDaniel Vetter * rotation. After reflection, the rotation is applied to the image sampled from 2501e4d84c6SDaniel Vetter * the source rectangle, before scaling it to fit the destination rectangle. 2511e4d84c6SDaniel Vetter */ 252d138dd3cSVille Syrjälä int drm_plane_create_rotation_property(struct drm_plane *plane, 253d138dd3cSVille Syrjälä unsigned int rotation, 254d138dd3cSVille Syrjälä unsigned int supported_rotations) 255d138dd3cSVille Syrjälä { 256d138dd3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 257c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_ROTATE_0) - 1, "rotate-0" }, 258c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_ROTATE_90) - 1, "rotate-90" }, 259c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" }, 260c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" }, 261c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_REFLECT_X) - 1, "reflect-x" }, 262c2c446adSRobert Foss { __builtin_ffs(DRM_MODE_REFLECT_Y) - 1, "reflect-y" }, 263d138dd3cSVille Syrjälä }; 264d138dd3cSVille Syrjälä struct drm_property *prop; 265d138dd3cSVille Syrjälä 266c2c446adSRobert Foss WARN_ON((supported_rotations & DRM_MODE_ROTATE_MASK) == 0); 267c2c446adSRobert Foss WARN_ON(!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK)); 268d138dd3cSVille Syrjälä WARN_ON(rotation & ~supported_rotations); 269d138dd3cSVille Syrjälä 270d138dd3cSVille Syrjälä prop = drm_property_create_bitmask(plane->dev, 0, "rotation", 271d138dd3cSVille Syrjälä props, ARRAY_SIZE(props), 272d138dd3cSVille Syrjälä supported_rotations); 273d138dd3cSVille Syrjälä if (!prop) 274d138dd3cSVille Syrjälä return -ENOMEM; 275d138dd3cSVille Syrjälä 276d138dd3cSVille Syrjälä drm_object_attach_property(&plane->base, prop, rotation); 277d138dd3cSVille Syrjälä 278d138dd3cSVille Syrjälä if (plane->state) 279d138dd3cSVille Syrjälä plane->state->rotation = rotation; 280d138dd3cSVille Syrjälä 281d138dd3cSVille Syrjälä plane->rotation_property = prop; 282d138dd3cSVille Syrjälä 283d138dd3cSVille Syrjälä return 0; 284d138dd3cSVille Syrjälä } 285d138dd3cSVille Syrjälä EXPORT_SYMBOL(drm_plane_create_rotation_property); 286d138dd3cSVille Syrjälä 28718733802SDaniel Vetter /** 28818733802SDaniel Vetter * drm_rotation_simplify() - Try to simplify the rotation 28918733802SDaniel Vetter * @rotation: Rotation to be simplified 29018733802SDaniel Vetter * @supported_rotations: Supported rotations 29118733802SDaniel Vetter * 29218733802SDaniel Vetter * Attempt to simplify the rotation to a form that is supported. 293c2c446adSRobert Foss * Eg. if the hardware supports everything except DRM_MODE_REFLECT_X 29418733802SDaniel Vetter * one could call this function like this: 29518733802SDaniel Vetter * 296c2c446adSRobert Foss * drm_rotation_simplify(rotation, DRM_MODE_ROTATE_0 | 297c2c446adSRobert Foss * DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 | 298c2c446adSRobert Foss * DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_Y); 29918733802SDaniel Vetter * 300c2c446adSRobert Foss * to eliminate the DRM_MODE_ROTATE_X flag. Depending on what kind of 30118733802SDaniel Vetter * transforms the hardware supports, this function may not 30218733802SDaniel Vetter * be able to produce a supported transform, so the caller should 30318733802SDaniel Vetter * check the result afterwards. 30418733802SDaniel Vetter */ 30518733802SDaniel Vetter unsigned int drm_rotation_simplify(unsigned int rotation, 30618733802SDaniel Vetter unsigned int supported_rotations) 30718733802SDaniel Vetter { 30818733802SDaniel Vetter if (rotation & ~supported_rotations) { 309c2c446adSRobert Foss rotation ^= DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; 310c2c446adSRobert Foss rotation = (rotation & DRM_MODE_REFLECT_MASK) | 311c2c446adSRobert Foss BIT((ffs(rotation & DRM_MODE_ROTATE_MASK) + 1) 312c2c446adSRobert Foss % 4); 31318733802SDaniel Vetter } 31418733802SDaniel Vetter 31518733802SDaniel Vetter return rotation; 31618733802SDaniel Vetter } 31718733802SDaniel Vetter EXPORT_SYMBOL(drm_rotation_simplify); 31818733802SDaniel Vetter 31944d1240dSMarek Szyprowski /** 32044d1240dSMarek Szyprowski * drm_plane_create_zpos_property - create mutable zpos property 32144d1240dSMarek Szyprowski * @plane: drm plane 32244d1240dSMarek Szyprowski * @zpos: initial value of zpos property 32344d1240dSMarek Szyprowski * @min: minimal possible value of zpos property 32444d1240dSMarek Szyprowski * @max: maximal possible value of zpos property 32544d1240dSMarek Szyprowski * 32644d1240dSMarek Szyprowski * This function initializes generic mutable zpos property and enables support 32744d1240dSMarek Szyprowski * for it in drm core. Drivers can then attach this property to planes to enable 32844d1240dSMarek Szyprowski * support for configurable planes arrangement during blending operation. 329ca40cfc8SThierry Reding * Drivers that attach a mutable zpos property to any plane should call the 330ca40cfc8SThierry Reding * drm_atomic_normalize_zpos() helper during their implementation of 331ca40cfc8SThierry Reding * &drm_mode_config_funcs.atomic_check(), which will update the normalized zpos 332ca40cfc8SThierry Reding * values and store them in &drm_plane_state.normalized_zpos. Usually min 333ca40cfc8SThierry Reding * should be set to 0 and max to maximal number of planes for given crtc - 1. 33444d1240dSMarek Szyprowski * 33544d1240dSMarek Szyprowski * If zpos of some planes cannot be changed (like fixed background or 33644d1240dSMarek Szyprowski * cursor/topmost planes), driver should adjust min/max values and assign those 33744d1240dSMarek Szyprowski * planes immutable zpos property with lower or higher values (for more 3381e4d84c6SDaniel Vetter * information, see drm_plane_create_zpos_immutable_property() function). In such 33944d1240dSMarek Szyprowski * case driver should also assign proper initial zpos values for all planes in 34044d1240dSMarek Szyprowski * its plane_reset() callback, so the planes will be always sorted properly. 34144d1240dSMarek Szyprowski * 3421e4d84c6SDaniel Vetter * See also drm_atomic_normalize_zpos(). 3431e4d84c6SDaniel Vetter * 3441e4d84c6SDaniel Vetter * The property exposed to userspace is called "zpos". 3451e4d84c6SDaniel Vetter * 34644d1240dSMarek Szyprowski * Returns: 34744d1240dSMarek Szyprowski * Zero on success, negative errno on failure. 34844d1240dSMarek Szyprowski */ 34944d1240dSMarek Szyprowski int drm_plane_create_zpos_property(struct drm_plane *plane, 35044d1240dSMarek Szyprowski unsigned int zpos, 35144d1240dSMarek Szyprowski unsigned int min, unsigned int max) 35244d1240dSMarek Szyprowski { 35344d1240dSMarek Szyprowski struct drm_property *prop; 35444d1240dSMarek Szyprowski 35544d1240dSMarek Szyprowski prop = drm_property_create_range(plane->dev, 0, "zpos", min, max); 35644d1240dSMarek Szyprowski if (!prop) 35744d1240dSMarek Szyprowski return -ENOMEM; 35844d1240dSMarek Szyprowski 35944d1240dSMarek Szyprowski drm_object_attach_property(&plane->base, prop, zpos); 36044d1240dSMarek Szyprowski 36144d1240dSMarek Szyprowski plane->zpos_property = prop; 36244d1240dSMarek Szyprowski 36344d1240dSMarek Szyprowski if (plane->state) { 36444d1240dSMarek Szyprowski plane->state->zpos = zpos; 36544d1240dSMarek Szyprowski plane->state->normalized_zpos = zpos; 36644d1240dSMarek Szyprowski } 36744d1240dSMarek Szyprowski 36844d1240dSMarek Szyprowski return 0; 36944d1240dSMarek Szyprowski } 37044d1240dSMarek Szyprowski EXPORT_SYMBOL(drm_plane_create_zpos_property); 37144d1240dSMarek Szyprowski 37244d1240dSMarek Szyprowski /** 37344d1240dSMarek Szyprowski * drm_plane_create_zpos_immutable_property - create immuttable zpos property 37444d1240dSMarek Szyprowski * @plane: drm plane 37544d1240dSMarek Szyprowski * @zpos: value of zpos property 37644d1240dSMarek Szyprowski * 37744d1240dSMarek Szyprowski * This function initializes generic immutable zpos property and enables 37844d1240dSMarek Szyprowski * support for it in drm core. Using this property driver lets userspace 37944d1240dSMarek Szyprowski * to get the arrangement of the planes for blending operation and notifies 38044d1240dSMarek Szyprowski * it that the hardware (or driver) doesn't support changing of the planes' 3811e4d84c6SDaniel Vetter * order. For mutable zpos see drm_plane_create_zpos_property(). 3821e4d84c6SDaniel Vetter * 3831e4d84c6SDaniel Vetter * The property exposed to userspace is called "zpos". 38444d1240dSMarek Szyprowski * 38544d1240dSMarek Szyprowski * Returns: 38644d1240dSMarek Szyprowski * Zero on success, negative errno on failure. 38744d1240dSMarek Szyprowski */ 38844d1240dSMarek Szyprowski int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, 38944d1240dSMarek Szyprowski unsigned int zpos) 39044d1240dSMarek Szyprowski { 39144d1240dSMarek Szyprowski struct drm_property *prop; 39244d1240dSMarek Szyprowski 39344d1240dSMarek Szyprowski prop = drm_property_create_range(plane->dev, DRM_MODE_PROP_IMMUTABLE, 39444d1240dSMarek Szyprowski "zpos", zpos, zpos); 39544d1240dSMarek Szyprowski if (!prop) 39644d1240dSMarek Szyprowski return -ENOMEM; 39744d1240dSMarek Szyprowski 39844d1240dSMarek Szyprowski drm_object_attach_property(&plane->base, prop, zpos); 39944d1240dSMarek Szyprowski 40044d1240dSMarek Szyprowski plane->zpos_property = prop; 40144d1240dSMarek Szyprowski 40244d1240dSMarek Szyprowski if (plane->state) { 40344d1240dSMarek Szyprowski plane->state->zpos = zpos; 40444d1240dSMarek Szyprowski plane->state->normalized_zpos = zpos; 40544d1240dSMarek Szyprowski } 40644d1240dSMarek Szyprowski 40744d1240dSMarek Szyprowski return 0; 40844d1240dSMarek Szyprowski } 40944d1240dSMarek Szyprowski EXPORT_SYMBOL(drm_plane_create_zpos_immutable_property); 41044d1240dSMarek Szyprowski 41144d1240dSMarek Szyprowski static int drm_atomic_state_zpos_cmp(const void *a, const void *b) 41244d1240dSMarek Szyprowski { 41344d1240dSMarek Szyprowski const struct drm_plane_state *sa = *(struct drm_plane_state **)a; 41444d1240dSMarek Szyprowski const struct drm_plane_state *sb = *(struct drm_plane_state **)b; 41544d1240dSMarek Szyprowski 41644d1240dSMarek Szyprowski if (sa->zpos != sb->zpos) 41744d1240dSMarek Szyprowski return sa->zpos - sb->zpos; 41844d1240dSMarek Szyprowski else 41944d1240dSMarek Szyprowski return sa->plane->base.id - sb->plane->base.id; 42044d1240dSMarek Szyprowski } 42144d1240dSMarek Szyprowski 42244d1240dSMarek Szyprowski static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, 42344d1240dSMarek Szyprowski struct drm_crtc_state *crtc_state) 42444d1240dSMarek Szyprowski { 42544d1240dSMarek Szyprowski struct drm_atomic_state *state = crtc_state->state; 42644d1240dSMarek Szyprowski struct drm_device *dev = crtc->dev; 42744d1240dSMarek Szyprowski int total_planes = dev->mode_config.num_total_plane; 42844d1240dSMarek Szyprowski struct drm_plane_state **states; 42944d1240dSMarek Szyprowski struct drm_plane *plane; 43044d1240dSMarek Szyprowski int i, n = 0; 43144d1240dSMarek Szyprowski int ret = 0; 43244d1240dSMarek Szyprowski 43344d1240dSMarek Szyprowski DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n", 43444d1240dSMarek Szyprowski crtc->base.id, crtc->name); 43544d1240dSMarek Szyprowski 4360ee931c4SMichal Hocko states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL); 43744d1240dSMarek Szyprowski if (!states) 43844d1240dSMarek Szyprowski return -ENOMEM; 43944d1240dSMarek Szyprowski 44044d1240dSMarek Szyprowski /* 44144d1240dSMarek Szyprowski * Normalization process might create new states for planes which 44244d1240dSMarek Szyprowski * normalized_zpos has to be recalculated. 44344d1240dSMarek Szyprowski */ 44444d1240dSMarek Szyprowski drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { 44544d1240dSMarek Szyprowski struct drm_plane_state *plane_state = 44644d1240dSMarek Szyprowski drm_atomic_get_plane_state(state, plane); 44744d1240dSMarek Szyprowski if (IS_ERR(plane_state)) { 44844d1240dSMarek Szyprowski ret = PTR_ERR(plane_state); 44944d1240dSMarek Szyprowski goto done; 45044d1240dSMarek Szyprowski } 45144d1240dSMarek Szyprowski states[n++] = plane_state; 45244d1240dSMarek Szyprowski DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n", 45344d1240dSMarek Szyprowski plane->base.id, plane->name, 45444d1240dSMarek Szyprowski plane_state->zpos); 45544d1240dSMarek Szyprowski } 45644d1240dSMarek Szyprowski 45744d1240dSMarek Szyprowski sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL); 45844d1240dSMarek Szyprowski 45944d1240dSMarek Szyprowski for (i = 0; i < n; i++) { 46044d1240dSMarek Szyprowski plane = states[i]->plane; 46144d1240dSMarek Szyprowski 46244d1240dSMarek Szyprowski states[i]->normalized_zpos = i; 46344d1240dSMarek Szyprowski DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n", 46444d1240dSMarek Szyprowski plane->base.id, plane->name, i); 46544d1240dSMarek Szyprowski } 46644d1240dSMarek Szyprowski crtc_state->zpos_changed = true; 46744d1240dSMarek Szyprowski 46844d1240dSMarek Szyprowski done: 46944d1240dSMarek Szyprowski kfree(states); 47044d1240dSMarek Szyprowski return ret; 47144d1240dSMarek Szyprowski } 47244d1240dSMarek Szyprowski 47344d1240dSMarek Szyprowski /** 47452a9fcdaSDaniel Vetter * drm_atomic_normalize_zpos - calculate normalized zpos values for all crtcs 47544d1240dSMarek Szyprowski * @dev: DRM device 47644d1240dSMarek Szyprowski * @state: atomic state of DRM device 47744d1240dSMarek Szyprowski * 47844d1240dSMarek Szyprowski * This function calculates normalized zpos value for all modified planes in 4791e4d84c6SDaniel Vetter * the provided atomic state of DRM device. 4801e4d84c6SDaniel Vetter * 4811e4d84c6SDaniel Vetter * For every CRTC this function checks new states of all planes assigned to 4821e4d84c6SDaniel Vetter * it and calculates normalized zpos value for these planes. Planes are compared 4831e4d84c6SDaniel Vetter * first by their zpos values, then by plane id (if zpos is equal). The plane 484d574528aSDaniel Vetter * with lowest zpos value is at the bottom. The &drm_plane_state.normalized_zpos 485d574528aSDaniel Vetter * is then filled with unique values from 0 to number of active planes in crtc 4861e4d84c6SDaniel Vetter * minus one. 48744d1240dSMarek Szyprowski * 48844d1240dSMarek Szyprowski * RETURNS 48944d1240dSMarek Szyprowski * Zero for success or -errno 49044d1240dSMarek Szyprowski */ 49152a9fcdaSDaniel Vetter int drm_atomic_normalize_zpos(struct drm_device *dev, 49244d1240dSMarek Szyprowski struct drm_atomic_state *state) 49344d1240dSMarek Szyprowski { 49444d1240dSMarek Szyprowski struct drm_crtc *crtc; 49562c7bdc0SMaarten Lankhorst struct drm_crtc_state *old_crtc_state, *new_crtc_state; 49644d1240dSMarek Szyprowski struct drm_plane *plane; 49762c7bdc0SMaarten Lankhorst struct drm_plane_state *old_plane_state, *new_plane_state; 49844d1240dSMarek Szyprowski int i, ret = 0; 49944d1240dSMarek Szyprowski 50062c7bdc0SMaarten Lankhorst for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { 50162c7bdc0SMaarten Lankhorst crtc = new_plane_state->crtc; 50244d1240dSMarek Szyprowski if (!crtc) 50344d1240dSMarek Szyprowski continue; 50462c7bdc0SMaarten Lankhorst if (old_plane_state->zpos != new_plane_state->zpos) { 50562c7bdc0SMaarten Lankhorst new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 50662c7bdc0SMaarten Lankhorst new_crtc_state->zpos_changed = true; 50744d1240dSMarek Szyprowski } 50844d1240dSMarek Szyprowski } 50944d1240dSMarek Szyprowski 51062c7bdc0SMaarten Lankhorst for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 51162c7bdc0SMaarten Lankhorst if (old_crtc_state->plane_mask != new_crtc_state->plane_mask || 51262c7bdc0SMaarten Lankhorst new_crtc_state->zpos_changed) { 51344d1240dSMarek Szyprowski ret = drm_atomic_helper_crtc_normalize_zpos(crtc, 51462c7bdc0SMaarten Lankhorst new_crtc_state); 51544d1240dSMarek Szyprowski if (ret) 51644d1240dSMarek Szyprowski return ret; 51744d1240dSMarek Szyprowski } 51844d1240dSMarek Szyprowski } 51944d1240dSMarek Szyprowski return 0; 52044d1240dSMarek Szyprowski } 52152a9fcdaSDaniel Vetter EXPORT_SYMBOL(drm_atomic_normalize_zpos); 522a5ec8332SLowry Li 523a5ec8332SLowry Li /** 524a5ec8332SLowry Li * drm_plane_create_blend_mode_property - create a new blend mode property 525a5ec8332SLowry Li * @plane: drm plane 526a5ec8332SLowry Li * @supported_modes: bitmask of supported modes, must include 527a5ec8332SLowry Li * BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is 528a5ec8332SLowry Li * that alpha is premultiplied, and old userspace can break if 529a5ec8332SLowry Li * the property defaults to anything else. 530a5ec8332SLowry Li * 531a5ec8332SLowry Li * This creates a new property describing the blend mode. 532a5ec8332SLowry Li * 533a5ec8332SLowry Li * The property exposed to userspace is an enumeration property (see 534a5ec8332SLowry Li * drm_property_create_enum()) called "pixel blend mode" and has the 535a5ec8332SLowry Li * following enumeration values: 536a5ec8332SLowry Li * 537a5ec8332SLowry Li * "None": 538a5ec8332SLowry Li * Blend formula that ignores the pixel alpha. 539a5ec8332SLowry Li * 540a5ec8332SLowry Li * "Pre-multiplied": 541a5ec8332SLowry Li * Blend formula that assumes the pixel color values have been already 542a5ec8332SLowry Li * pre-multiplied with the alpha channel values. 543a5ec8332SLowry Li * 544a5ec8332SLowry Li * "Coverage": 545a5ec8332SLowry Li * Blend formula that assumes the pixel color values have not been 546a5ec8332SLowry Li * pre-multiplied and will do so when blending them to the background color 547a5ec8332SLowry Li * values. 548a5ec8332SLowry Li * 549a5ec8332SLowry Li * RETURNS: 550a5ec8332SLowry Li * Zero for success or -errno 551a5ec8332SLowry Li */ 552a5ec8332SLowry Li int drm_plane_create_blend_mode_property(struct drm_plane *plane, 553a5ec8332SLowry Li unsigned int supported_modes) 554a5ec8332SLowry Li { 555a5ec8332SLowry Li struct drm_device *dev = plane->dev; 556a5ec8332SLowry Li struct drm_property *prop; 557a5ec8332SLowry Li static const struct drm_prop_enum_list props[] = { 558a5ec8332SLowry Li { DRM_MODE_BLEND_PIXEL_NONE, "None" }, 559a5ec8332SLowry Li { DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" }, 560a5ec8332SLowry Li { DRM_MODE_BLEND_COVERAGE, "Coverage" }, 561a5ec8332SLowry Li }; 562a5ec8332SLowry Li unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) | 563a5ec8332SLowry Li BIT(DRM_MODE_BLEND_PREMULTI) | 564a5ec8332SLowry Li BIT(DRM_MODE_BLEND_COVERAGE); 565a5ec8332SLowry Li int i; 566a5ec8332SLowry Li 567a5ec8332SLowry Li if (WARN_ON((supported_modes & ~valid_mode_mask) || 568a5ec8332SLowry Li ((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0))) 569a5ec8332SLowry Li return -EINVAL; 570a5ec8332SLowry Li 571a5ec8332SLowry Li prop = drm_property_create(dev, DRM_MODE_PROP_ENUM, 572a5ec8332SLowry Li "pixel blend mode", 573a5ec8332SLowry Li hweight32(supported_modes)); 574a5ec8332SLowry Li if (!prop) 575a5ec8332SLowry Li return -ENOMEM; 576a5ec8332SLowry Li 577a5ec8332SLowry Li for (i = 0; i < ARRAY_SIZE(props); i++) { 578a5ec8332SLowry Li int ret; 579a5ec8332SLowry Li 580a5ec8332SLowry Li if (!(BIT(props[i].type) & supported_modes)) 581a5ec8332SLowry Li continue; 582a5ec8332SLowry Li 583a5ec8332SLowry Li ret = drm_property_add_enum(prop, props[i].type, 584a5ec8332SLowry Li props[i].name); 585a5ec8332SLowry Li 586a5ec8332SLowry Li if (ret) { 587a5ec8332SLowry Li drm_property_destroy(dev, prop); 588a5ec8332SLowry Li 589a5ec8332SLowry Li return ret; 590a5ec8332SLowry Li } 591a5ec8332SLowry Li } 592a5ec8332SLowry Li 593a5ec8332SLowry Li drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI); 594a5ec8332SLowry Li plane->blend_mode_property = prop; 595a5ec8332SLowry Li 596a5ec8332SLowry Li return 0; 597a5ec8332SLowry Li } 598a5ec8332SLowry Li EXPORT_SYMBOL(drm_plane_create_blend_mode_property); 599