13512f976SVille Syrjälä /* 23512f976SVille Syrjälä * Copyright (C) 2011-2013 Intel Corporation 33512f976SVille Syrjälä * 43512f976SVille Syrjälä * Permission is hereby granted, free of charge, to any person obtaining a 53512f976SVille Syrjälä * copy of this software and associated documentation files (the "Software"), 63512f976SVille Syrjälä * to deal in the Software without restriction, including without limitation 73512f976SVille Syrjälä * the rights to use, copy, modify, merge, publish, distribute, sublicense, 83512f976SVille Syrjälä * and/or sell copies of the Software, and to permit persons to whom the 93512f976SVille Syrjälä * Software is furnished to do so, subject to the following conditions: 103512f976SVille Syrjälä * 113512f976SVille Syrjälä * The above copyright notice and this permission notice (including the next 123512f976SVille Syrjälä * paragraph) shall be included in all copies or substantial portions of the 133512f976SVille Syrjälä * Software. 143512f976SVille Syrjälä * 153512f976SVille Syrjälä * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 163512f976SVille Syrjälä * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 173512f976SVille Syrjälä * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 183512f976SVille Syrjälä * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 193512f976SVille Syrjälä * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 203512f976SVille Syrjälä * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 213512f976SVille Syrjälä * SOFTWARE. 223512f976SVille Syrjälä */ 233512f976SVille Syrjälä 243512f976SVille Syrjälä #include <linux/errno.h> 253512f976SVille Syrjälä #include <linux/export.h> 263512f976SVille Syrjälä #include <linux/kernel.h> 270500c04eSSam Ravnborg 280500c04eSSam Ravnborg #include <drm/drm_mode.h> 290500c04eSSam Ravnborg #include <drm/drm_print.h> 303512f976SVille Syrjälä #include <drm/drm_rect.h> 313512f976SVille Syrjälä 323512f976SVille Syrjälä /** 333512f976SVille Syrjälä * drm_rect_intersect - intersect two rectangles 343512f976SVille Syrjälä * @r1: first rectangle 353512f976SVille Syrjälä * @r2: second rectangle 363512f976SVille Syrjälä * 373512f976SVille Syrjälä * Calculate the intersection of rectangles @r1 and @r2. 383512f976SVille Syrjälä * @r1 will be overwritten with the intersection. 393512f976SVille Syrjälä * 403512f976SVille Syrjälä * RETURNS: 413512f976SVille Syrjälä * %true if rectangle @r1 is still visible after the operation, 423512f976SVille Syrjälä * %false otherwise. 433512f976SVille Syrjälä */ 443512f976SVille Syrjälä bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2) 453512f976SVille Syrjälä { 463512f976SVille Syrjälä r1->x1 = max(r1->x1, r2->x1); 473512f976SVille Syrjälä r1->y1 = max(r1->y1, r2->y1); 483512f976SVille Syrjälä r1->x2 = min(r1->x2, r2->x2); 493512f976SVille Syrjälä r1->y2 = min(r1->y2, r2->y2); 503512f976SVille Syrjälä 513512f976SVille Syrjälä return drm_rect_visible(r1); 523512f976SVille Syrjälä } 533512f976SVille Syrjälä EXPORT_SYMBOL(drm_rect_intersect); 543512f976SVille Syrjälä 552020af2dSVille Syrjälä static u32 clip_scaled(int src, int dst, int *clip) 56f96bdf56SMaarten Lankhorst { 57433480c1SVille Syrjälä u64 tmp; 58433480c1SVille Syrjälä 59433480c1SVille Syrjälä if (dst == 0) 60433480c1SVille Syrjälä return 0; 61433480c1SVille Syrjälä 622e351705SVille Syrjälä /* Only clip what we have. Keeps the result bounded. */ 632020af2dSVille Syrjälä *clip = min(*clip, dst); 642e351705SVille Syrjälä 652020af2dSVille Syrjälä tmp = mul_u32_u32(src, dst - *clip); 66f96bdf56SMaarten Lankhorst 67f96bdf56SMaarten Lankhorst /* 68f96bdf56SMaarten Lankhorst * Round toward 1.0 when clipping so that we don't accidentally 69f96bdf56SMaarten Lankhorst * change upscaling to downscaling or vice versa. 70f96bdf56SMaarten Lankhorst */ 71f96bdf56SMaarten Lankhorst if (src < (dst << 16)) 72f96bdf56SMaarten Lankhorst return DIV_ROUND_UP_ULL(tmp, dst); 73f96bdf56SMaarten Lankhorst else 74f96bdf56SMaarten Lankhorst return DIV_ROUND_DOWN_ULL(tmp, dst); 75f96bdf56SMaarten Lankhorst } 76f96bdf56SMaarten Lankhorst 773512f976SVille Syrjälä /** 783512f976SVille Syrjälä * drm_rect_clip_scaled - perform a scaled clip operation 793512f976SVille Syrjälä * @src: source window rectangle 803512f976SVille Syrjälä * @dst: destination window rectangle 813512f976SVille Syrjälä * @clip: clip rectangle 823512f976SVille Syrjälä * 83*2556e1a8Swangjianli * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by 8494fee4a7SDaniel Vetter * the corresponding amounts, retaining the vertical and horizontal scaling 8594fee4a7SDaniel Vetter * factors from @src to @dst. 863512f976SVille Syrjälä * 873512f976SVille Syrjälä * RETURNS: 883512f976SVille Syrjälä * %true if rectangle @dst is still visible after being clipped, 8994fee4a7SDaniel Vetter * %false otherwise. 903512f976SVille Syrjälä */ 913512f976SVille Syrjälä bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 92f96bdf56SMaarten Lankhorst const struct drm_rect *clip) 933512f976SVille Syrjälä { 943512f976SVille Syrjälä int diff; 953512f976SVille Syrjälä 963512f976SVille Syrjälä diff = clip->x1 - dst->x1; 973512f976SVille Syrjälä if (diff > 0) { 98f96bdf56SMaarten Lankhorst u32 new_src_w = clip_scaled(drm_rect_width(src), 992020af2dSVille Syrjälä drm_rect_width(dst), &diff); 100f96bdf56SMaarten Lankhorst 1012e351705SVille Syrjälä src->x1 = src->x2 - new_src_w; 1022020af2dSVille Syrjälä dst->x1 += diff; 1033512f976SVille Syrjälä } 1043512f976SVille Syrjälä diff = clip->y1 - dst->y1; 1053512f976SVille Syrjälä if (diff > 0) { 106f96bdf56SMaarten Lankhorst u32 new_src_h = clip_scaled(drm_rect_height(src), 1072020af2dSVille Syrjälä drm_rect_height(dst), &diff); 108f96bdf56SMaarten Lankhorst 1092e351705SVille Syrjälä src->y1 = src->y2 - new_src_h; 1102020af2dSVille Syrjälä dst->y1 += diff; 1113512f976SVille Syrjälä } 1123512f976SVille Syrjälä diff = dst->x2 - clip->x2; 1133512f976SVille Syrjälä if (diff > 0) { 114f96bdf56SMaarten Lankhorst u32 new_src_w = clip_scaled(drm_rect_width(src), 1152020af2dSVille Syrjälä drm_rect_width(dst), &diff); 116f96bdf56SMaarten Lankhorst 1172e351705SVille Syrjälä src->x2 = src->x1 + new_src_w; 1182020af2dSVille Syrjälä dst->x2 -= diff; 1193512f976SVille Syrjälä } 1203512f976SVille Syrjälä diff = dst->y2 - clip->y2; 1213512f976SVille Syrjälä if (diff > 0) { 122f96bdf56SMaarten Lankhorst u32 new_src_h = clip_scaled(drm_rect_height(src), 1232020af2dSVille Syrjälä drm_rect_height(dst), &diff); 124f96bdf56SMaarten Lankhorst 1252e351705SVille Syrjälä src->y2 = src->y1 + new_src_h; 1262020af2dSVille Syrjälä dst->y2 -= diff; 1273512f976SVille Syrjälä } 1283512f976SVille Syrjälä 129f96bdf56SMaarten Lankhorst return drm_rect_visible(dst); 1303512f976SVille Syrjälä } 1313512f976SVille Syrjälä EXPORT_SYMBOL(drm_rect_clip_scaled); 1324954c428SVille Syrjälä 1334954c428SVille Syrjälä static int drm_calc_scale(int src, int dst) 1344954c428SVille Syrjälä { 1354954c428SVille Syrjälä int scale = 0; 1364954c428SVille Syrjälä 1371e1a5f8fSVille Syrjälä if (WARN_ON(src < 0 || dst < 0)) 1384954c428SVille Syrjälä return -EINVAL; 1394954c428SVille Syrjälä 1404954c428SVille Syrjälä if (dst == 0) 1414954c428SVille Syrjälä return 0; 1424954c428SVille Syrjälä 1436f96f200SMaarten Lankhorst if (src > (dst << 16)) 1446f96f200SMaarten Lankhorst return DIV_ROUND_UP(src, dst); 1456f96f200SMaarten Lankhorst else 1464954c428SVille Syrjälä scale = src / dst; 1474954c428SVille Syrjälä 1484954c428SVille Syrjälä return scale; 1494954c428SVille Syrjälä } 1504954c428SVille Syrjälä 1514954c428SVille Syrjälä /** 1524954c428SVille Syrjälä * drm_rect_calc_hscale - calculate the horizontal scaling factor 1534954c428SVille Syrjälä * @src: source window rectangle 1544954c428SVille Syrjälä * @dst: destination window rectangle 1554954c428SVille Syrjälä * @min_hscale: minimum allowed horizontal scaling factor 1564954c428SVille Syrjälä * @max_hscale: maximum allowed horizontal scaling factor 1574954c428SVille Syrjälä * 1584954c428SVille Syrjälä * Calculate the horizontal scaling factor as 1594954c428SVille Syrjälä * (@src width) / (@dst width). 1604954c428SVille Syrjälä * 1616f96f200SMaarten Lankhorst * If the scale is below 1 << 16, round down. If the scale is above 1626f96f200SMaarten Lankhorst * 1 << 16, round up. This will calculate the scale with the most 1636f96f200SMaarten Lankhorst * pessimistic limit calculation. 1646f96f200SMaarten Lankhorst * 1654954c428SVille Syrjälä * RETURNS: 1664954c428SVille Syrjälä * The horizontal scaling factor, or errno of out of limits. 1674954c428SVille Syrjälä */ 1684954c428SVille Syrjälä int drm_rect_calc_hscale(const struct drm_rect *src, 1694954c428SVille Syrjälä const struct drm_rect *dst, 1704954c428SVille Syrjälä int min_hscale, int max_hscale) 1714954c428SVille Syrjälä { 1724954c428SVille Syrjälä int src_w = drm_rect_width(src); 1734954c428SVille Syrjälä int dst_w = drm_rect_width(dst); 1744954c428SVille Syrjälä int hscale = drm_calc_scale(src_w, dst_w); 1754954c428SVille Syrjälä 1764954c428SVille Syrjälä if (hscale < 0 || dst_w == 0) 1774954c428SVille Syrjälä return hscale; 1784954c428SVille Syrjälä 1794954c428SVille Syrjälä if (hscale < min_hscale || hscale > max_hscale) 1804954c428SVille Syrjälä return -ERANGE; 1814954c428SVille Syrjälä 1824954c428SVille Syrjälä return hscale; 1834954c428SVille Syrjälä } 1844954c428SVille Syrjälä EXPORT_SYMBOL(drm_rect_calc_hscale); 1854954c428SVille Syrjälä 1864954c428SVille Syrjälä /** 1874954c428SVille Syrjälä * drm_rect_calc_vscale - calculate the vertical scaling factor 1884954c428SVille Syrjälä * @src: source window rectangle 1894954c428SVille Syrjälä * @dst: destination window rectangle 1904954c428SVille Syrjälä * @min_vscale: minimum allowed vertical scaling factor 1914954c428SVille Syrjälä * @max_vscale: maximum allowed vertical scaling factor 1924954c428SVille Syrjälä * 1934954c428SVille Syrjälä * Calculate the vertical scaling factor as 1944954c428SVille Syrjälä * (@src height) / (@dst height). 1954954c428SVille Syrjälä * 1966f96f200SMaarten Lankhorst * If the scale is below 1 << 16, round down. If the scale is above 1976f96f200SMaarten Lankhorst * 1 << 16, round up. This will calculate the scale with the most 1986f96f200SMaarten Lankhorst * pessimistic limit calculation. 1996f96f200SMaarten Lankhorst * 2004954c428SVille Syrjälä * RETURNS: 2014954c428SVille Syrjälä * The vertical scaling factor, or errno of out of limits. 2024954c428SVille Syrjälä */ 2034954c428SVille Syrjälä int drm_rect_calc_vscale(const struct drm_rect *src, 2044954c428SVille Syrjälä const struct drm_rect *dst, 2054954c428SVille Syrjälä int min_vscale, int max_vscale) 2064954c428SVille Syrjälä { 2074954c428SVille Syrjälä int src_h = drm_rect_height(src); 2084954c428SVille Syrjälä int dst_h = drm_rect_height(dst); 2094954c428SVille Syrjälä int vscale = drm_calc_scale(src_h, dst_h); 2104954c428SVille Syrjälä 2114954c428SVille Syrjälä if (vscale < 0 || dst_h == 0) 2124954c428SVille Syrjälä return vscale; 2134954c428SVille Syrjälä 2144954c428SVille Syrjälä if (vscale < min_vscale || vscale > max_vscale) 2154954c428SVille Syrjälä return -ERANGE; 2164954c428SVille Syrjälä 2174954c428SVille Syrjälä return vscale; 2184954c428SVille Syrjälä } 2194954c428SVille Syrjälä EXPORT_SYMBOL(drm_rect_calc_vscale); 2204954c428SVille Syrjälä 2214954c428SVille Syrjälä /** 222e7272df3SVille Syrjälä * drm_rect_debug_print - print the rectangle information 223c70f577aSVille Syrjälä * @prefix: prefix string 224e7272df3SVille Syrjälä * @r: rectangle to print 225e7272df3SVille Syrjälä * @fixed_point: rectangle is in 16.16 fixed point format 226e7272df3SVille Syrjälä */ 227c70f577aSVille Syrjälä void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) 228e7272df3SVille Syrjälä { 229e7272df3SVille Syrjälä if (fixed_point) 23065c7dc18SRob Clark DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r)); 231e7272df3SVille Syrjälä else 23265c7dc18SRob Clark DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r)); 233e7272df3SVille Syrjälä } 234e7272df3SVille Syrjälä EXPORT_SYMBOL(drm_rect_debug_print); 23507074006SVille Syrjälä 23607074006SVille Syrjälä /** 23707074006SVille Syrjälä * drm_rect_rotate - Rotate the rectangle 23807074006SVille Syrjälä * @r: rectangle to be rotated 23907074006SVille Syrjälä * @width: Width of the coordinate space 24007074006SVille Syrjälä * @height: Height of the coordinate space 24107074006SVille Syrjälä * @rotation: Transformation to be applied 24207074006SVille Syrjälä * 24307074006SVille Syrjälä * Apply @rotation to the coordinates of rectangle @r. 24407074006SVille Syrjälä * 24507074006SVille Syrjälä * @width and @height combined with @rotation define 24607074006SVille Syrjälä * the location of the new origin. 24707074006SVille Syrjälä * 24807074006SVille Syrjälä * @width correcsponds to the horizontal and @height 24907074006SVille Syrjälä * to the vertical axis of the untransformed coordinate 25007074006SVille Syrjälä * space. 25107074006SVille Syrjälä */ 25207074006SVille Syrjälä void drm_rect_rotate(struct drm_rect *r, 25307074006SVille Syrjälä int width, int height, 25407074006SVille Syrjälä unsigned int rotation) 25507074006SVille Syrjälä { 25607074006SVille Syrjälä struct drm_rect tmp; 25707074006SVille Syrjälä 258c2c446adSRobert Foss if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 25907074006SVille Syrjälä tmp = *r; 26007074006SVille Syrjälä 261c2c446adSRobert Foss if (rotation & DRM_MODE_REFLECT_X) { 26207074006SVille Syrjälä r->x1 = width - tmp.x2; 26307074006SVille Syrjälä r->x2 = width - tmp.x1; 26407074006SVille Syrjälä } 26507074006SVille Syrjälä 266c2c446adSRobert Foss if (rotation & DRM_MODE_REFLECT_Y) { 26707074006SVille Syrjälä r->y1 = height - tmp.y2; 26807074006SVille Syrjälä r->y2 = height - tmp.y1; 26907074006SVille Syrjälä } 27007074006SVille Syrjälä } 27107074006SVille Syrjälä 272c2c446adSRobert Foss switch (rotation & DRM_MODE_ROTATE_MASK) { 273c2c446adSRobert Foss case DRM_MODE_ROTATE_0: 27407074006SVille Syrjälä break; 275c2c446adSRobert Foss case DRM_MODE_ROTATE_90: 27607074006SVille Syrjälä tmp = *r; 27707074006SVille Syrjälä r->x1 = tmp.y1; 27807074006SVille Syrjälä r->x2 = tmp.y2; 27907074006SVille Syrjälä r->y1 = width - tmp.x2; 28007074006SVille Syrjälä r->y2 = width - tmp.x1; 28107074006SVille Syrjälä break; 282c2c446adSRobert Foss case DRM_MODE_ROTATE_180: 28307074006SVille Syrjälä tmp = *r; 28407074006SVille Syrjälä r->x1 = width - tmp.x2; 28507074006SVille Syrjälä r->x2 = width - tmp.x1; 28607074006SVille Syrjälä r->y1 = height - tmp.y2; 28707074006SVille Syrjälä r->y2 = height - tmp.y1; 28807074006SVille Syrjälä break; 289c2c446adSRobert Foss case DRM_MODE_ROTATE_270: 29007074006SVille Syrjälä tmp = *r; 29107074006SVille Syrjälä r->x1 = height - tmp.y2; 29207074006SVille Syrjälä r->x2 = height - tmp.y1; 29307074006SVille Syrjälä r->y1 = tmp.x1; 29407074006SVille Syrjälä r->y2 = tmp.x2; 29507074006SVille Syrjälä break; 29607074006SVille Syrjälä default: 29707074006SVille Syrjälä break; 29807074006SVille Syrjälä } 29907074006SVille Syrjälä } 30007074006SVille Syrjälä EXPORT_SYMBOL(drm_rect_rotate); 30107074006SVille Syrjälä 30207074006SVille Syrjälä /** 30307074006SVille Syrjälä * drm_rect_rotate_inv - Inverse rotate the rectangle 30407074006SVille Syrjälä * @r: rectangle to be rotated 30507074006SVille Syrjälä * @width: Width of the coordinate space 30607074006SVille Syrjälä * @height: Height of the coordinate space 30707074006SVille Syrjälä * @rotation: Transformation whose inverse is to be applied 30807074006SVille Syrjälä * 30907074006SVille Syrjälä * Apply the inverse of @rotation to the coordinates 31007074006SVille Syrjälä * of rectangle @r. 31107074006SVille Syrjälä * 31207074006SVille Syrjälä * @width and @height combined with @rotation define 31307074006SVille Syrjälä * the location of the new origin. 31407074006SVille Syrjälä * 31507074006SVille Syrjälä * @width correcsponds to the horizontal and @height 31607074006SVille Syrjälä * to the vertical axis of the original untransformed 31707074006SVille Syrjälä * coordinate space, so that you never have to flip 31807074006SVille Syrjälä * them when doing a rotatation and its inverse. 3195edbfc47SDaniel Vetter * That is, if you do :: 32007074006SVille Syrjälä * 321ec667231SVille Syrjälä * drm_rect_rotate(&r, width, height, rotation); 322ec667231SVille Syrjälä * drm_rect_rotate_inv(&r, width, height, rotation); 32307074006SVille Syrjälä * 32407074006SVille Syrjälä * you will always get back the original rectangle. 32507074006SVille Syrjälä */ 32607074006SVille Syrjälä void drm_rect_rotate_inv(struct drm_rect *r, 32707074006SVille Syrjälä int width, int height, 32807074006SVille Syrjälä unsigned int rotation) 32907074006SVille Syrjälä { 33007074006SVille Syrjälä struct drm_rect tmp; 33107074006SVille Syrjälä 332c2c446adSRobert Foss switch (rotation & DRM_MODE_ROTATE_MASK) { 333c2c446adSRobert Foss case DRM_MODE_ROTATE_0: 33407074006SVille Syrjälä break; 335c2c446adSRobert Foss case DRM_MODE_ROTATE_90: 33607074006SVille Syrjälä tmp = *r; 33707074006SVille Syrjälä r->x1 = width - tmp.y2; 33807074006SVille Syrjälä r->x2 = width - tmp.y1; 33907074006SVille Syrjälä r->y1 = tmp.x1; 34007074006SVille Syrjälä r->y2 = tmp.x2; 34107074006SVille Syrjälä break; 342c2c446adSRobert Foss case DRM_MODE_ROTATE_180: 34307074006SVille Syrjälä tmp = *r; 34407074006SVille Syrjälä r->x1 = width - tmp.x2; 34507074006SVille Syrjälä r->x2 = width - tmp.x1; 34607074006SVille Syrjälä r->y1 = height - tmp.y2; 34707074006SVille Syrjälä r->y2 = height - tmp.y1; 34807074006SVille Syrjälä break; 349c2c446adSRobert Foss case DRM_MODE_ROTATE_270: 35007074006SVille Syrjälä tmp = *r; 35107074006SVille Syrjälä r->x1 = tmp.y1; 35207074006SVille Syrjälä r->x2 = tmp.y2; 35307074006SVille Syrjälä r->y1 = height - tmp.x2; 35407074006SVille Syrjälä r->y2 = height - tmp.x1; 35507074006SVille Syrjälä break; 35607074006SVille Syrjälä default: 35707074006SVille Syrjälä break; 35807074006SVille Syrjälä } 35907074006SVille Syrjälä 360c2c446adSRobert Foss if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 36107074006SVille Syrjälä tmp = *r; 36207074006SVille Syrjälä 363c2c446adSRobert Foss if (rotation & DRM_MODE_REFLECT_X) { 36407074006SVille Syrjälä r->x1 = width - tmp.x2; 36507074006SVille Syrjälä r->x2 = width - tmp.x1; 36607074006SVille Syrjälä } 36707074006SVille Syrjälä 368c2c446adSRobert Foss if (rotation & DRM_MODE_REFLECT_Y) { 36907074006SVille Syrjälä r->y1 = height - tmp.y2; 37007074006SVille Syrjälä r->y2 = height - tmp.y1; 37107074006SVille Syrjälä } 37207074006SVille Syrjälä } 37307074006SVille Syrjälä } 37407074006SVille Syrjälä EXPORT_SYMBOL(drm_rect_rotate_inv); 375