1e1001332Skettenis /* 2e1001332Skettenis * Copyright (C) 2011-2013 Intel Corporation 3e1001332Skettenis * 4e1001332Skettenis * Permission is hereby granted, free of charge, to any person obtaining a 5e1001332Skettenis * copy of this software and associated documentation files (the "Software"), 6e1001332Skettenis * to deal in the Software without restriction, including without limitation 7e1001332Skettenis * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e1001332Skettenis * and/or sell copies of the Software, and to permit persons to whom the 9e1001332Skettenis * Software is furnished to do so, subject to the following conditions: 10e1001332Skettenis * 11e1001332Skettenis * The above copyright notice and this permission notice (including the next 12e1001332Skettenis * paragraph) shall be included in all copies or substantial portions of the 13e1001332Skettenis * Software. 14e1001332Skettenis * 15e1001332Skettenis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16e1001332Skettenis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17e1001332Skettenis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18e1001332Skettenis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19e1001332Skettenis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20e1001332Skettenis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21e1001332Skettenis * SOFTWARE. 22e1001332Skettenis */ 23e1001332Skettenis 243253c27bSkettenis #include <linux/errno.h> 253253c27bSkettenis #include <linux/export.h> 263253c27bSkettenis #include <linux/kernel.h> 27*c349dbc7Sjsg 28*c349dbc7Sjsg #include <drm/drm_mode.h> 29*c349dbc7Sjsg #include <drm/drm_print.h> 307f4dd379Sjsg #include <drm/drm_rect.h> 31e1001332Skettenis 32e1001332Skettenis /** 33e1001332Skettenis * drm_rect_intersect - intersect two rectangles 34e1001332Skettenis * @r1: first rectangle 35e1001332Skettenis * @r2: second rectangle 36e1001332Skettenis * 37e1001332Skettenis * Calculate the intersection of rectangles @r1 and @r2. 38e1001332Skettenis * @r1 will be overwritten with the intersection. 39e1001332Skettenis * 40e1001332Skettenis * RETURNS: 41e1001332Skettenis * %true if rectangle @r1 is still visible after the operation, 42e1001332Skettenis * %false otherwise. 43e1001332Skettenis */ 44e1001332Skettenis bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2) 45e1001332Skettenis { 46e1001332Skettenis r1->x1 = max(r1->x1, r2->x1); 47e1001332Skettenis r1->y1 = max(r1->y1, r2->y1); 48e1001332Skettenis r1->x2 = min(r1->x2, r2->x2); 49e1001332Skettenis r1->y2 = min(r1->y2, r2->y2); 50e1001332Skettenis 51e1001332Skettenis return drm_rect_visible(r1); 52e1001332Skettenis } 53e1001332Skettenis EXPORT_SYMBOL(drm_rect_intersect); 54e1001332Skettenis 55*c349dbc7Sjsg static u32 clip_scaled(int src, int dst, int *clip) 567f4dd379Sjsg { 57b06b705dSjsg u64 tmp; 58b06b705dSjsg 59b06b705dSjsg if (dst == 0) 60b06b705dSjsg return 0; 61b06b705dSjsg 62*c349dbc7Sjsg /* Only clip what we have. Keeps the result bounded. */ 63*c349dbc7Sjsg *clip = min(*clip, dst); 64*c349dbc7Sjsg 65*c349dbc7Sjsg tmp = mul_u32_u32(src, dst - *clip); 667f4dd379Sjsg 677f4dd379Sjsg /* 687f4dd379Sjsg * Round toward 1.0 when clipping so that we don't accidentally 697f4dd379Sjsg * change upscaling to downscaling or vice versa. 707f4dd379Sjsg */ 717f4dd379Sjsg if (src < (dst << 16)) 727f4dd379Sjsg return DIV_ROUND_UP_ULL(tmp, dst); 737f4dd379Sjsg else 747f4dd379Sjsg return DIV_ROUND_DOWN_ULL(tmp, dst); 757f4dd379Sjsg } 767f4dd379Sjsg 77e1001332Skettenis /** 78e1001332Skettenis * drm_rect_clip_scaled - perform a scaled clip operation 79e1001332Skettenis * @src: source window rectangle 80e1001332Skettenis * @dst: destination window rectangle 81e1001332Skettenis * @clip: clip rectangle 82e1001332Skettenis * 83e1001332Skettenis * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the 84*c349dbc7Sjsg * the corresponding amounts, retaining the vertical and horizontal scaling 85*c349dbc7Sjsg * factors from @src to @dst. 86e1001332Skettenis * 87e1001332Skettenis * RETURNS: 88*c349dbc7Sjsg * 89e1001332Skettenis * %true if rectangle @dst is still visible after being clipped, 90*c349dbc7Sjsg * %false otherwise. 91e1001332Skettenis */ 92e1001332Skettenis bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 937f4dd379Sjsg const struct drm_rect *clip) 94e1001332Skettenis { 95e1001332Skettenis int diff; 96e1001332Skettenis 97e1001332Skettenis diff = clip->x1 - dst->x1; 98e1001332Skettenis if (diff > 0) { 997f4dd379Sjsg u32 new_src_w = clip_scaled(drm_rect_width(src), 100*c349dbc7Sjsg drm_rect_width(dst), &diff); 1017f4dd379Sjsg 102*c349dbc7Sjsg src->x1 = src->x2 - new_src_w; 103*c349dbc7Sjsg dst->x1 += diff; 104e1001332Skettenis } 105e1001332Skettenis diff = clip->y1 - dst->y1; 106e1001332Skettenis if (diff > 0) { 1077f4dd379Sjsg u32 new_src_h = clip_scaled(drm_rect_height(src), 108*c349dbc7Sjsg drm_rect_height(dst), &diff); 1097f4dd379Sjsg 110*c349dbc7Sjsg src->y1 = src->y2 - new_src_h; 111*c349dbc7Sjsg dst->y1 += diff; 112e1001332Skettenis } 113e1001332Skettenis diff = dst->x2 - clip->x2; 114e1001332Skettenis if (diff > 0) { 1157f4dd379Sjsg u32 new_src_w = clip_scaled(drm_rect_width(src), 116*c349dbc7Sjsg drm_rect_width(dst), &diff); 1177f4dd379Sjsg 118*c349dbc7Sjsg src->x2 = src->x1 + new_src_w; 119*c349dbc7Sjsg dst->x2 -= diff; 120e1001332Skettenis } 121e1001332Skettenis diff = dst->y2 - clip->y2; 122e1001332Skettenis if (diff > 0) { 1237f4dd379Sjsg u32 new_src_h = clip_scaled(drm_rect_height(src), 124*c349dbc7Sjsg drm_rect_height(dst), &diff); 1257f4dd379Sjsg 126*c349dbc7Sjsg src->y2 = src->y1 + new_src_h; 127*c349dbc7Sjsg dst->y2 -= diff; 128e1001332Skettenis } 129e1001332Skettenis 1307f4dd379Sjsg return drm_rect_visible(dst); 131e1001332Skettenis } 132e1001332Skettenis EXPORT_SYMBOL(drm_rect_clip_scaled); 133e1001332Skettenis 134e1001332Skettenis static int drm_calc_scale(int src, int dst) 135e1001332Skettenis { 136e1001332Skettenis int scale = 0; 137e1001332Skettenis 1387f4dd379Sjsg if (WARN_ON(src < 0 || dst < 0)) 139e1001332Skettenis return -EINVAL; 140e1001332Skettenis 141e1001332Skettenis if (dst == 0) 142e1001332Skettenis return 0; 143e1001332Skettenis 1447f4dd379Sjsg if (src > (dst << 16)) 1457f4dd379Sjsg return DIV_ROUND_UP(src, dst); 1467f4dd379Sjsg else 147e1001332Skettenis scale = src / dst; 148e1001332Skettenis 149e1001332Skettenis return scale; 150e1001332Skettenis } 151e1001332Skettenis 152e1001332Skettenis /** 153e1001332Skettenis * drm_rect_calc_hscale - calculate the horizontal scaling factor 154e1001332Skettenis * @src: source window rectangle 155e1001332Skettenis * @dst: destination window rectangle 156e1001332Skettenis * @min_hscale: minimum allowed horizontal scaling factor 157e1001332Skettenis * @max_hscale: maximum allowed horizontal scaling factor 158e1001332Skettenis * 159e1001332Skettenis * Calculate the horizontal scaling factor as 160e1001332Skettenis * (@src width) / (@dst width). 161e1001332Skettenis * 1627f4dd379Sjsg * If the scale is below 1 << 16, round down. If the scale is above 1637f4dd379Sjsg * 1 << 16, round up. This will calculate the scale with the most 1647f4dd379Sjsg * pessimistic limit calculation. 1657f4dd379Sjsg * 166e1001332Skettenis * RETURNS: 167e1001332Skettenis * The horizontal scaling factor, or errno of out of limits. 168e1001332Skettenis */ 169e1001332Skettenis int drm_rect_calc_hscale(const struct drm_rect *src, 170e1001332Skettenis const struct drm_rect *dst, 171e1001332Skettenis int min_hscale, int max_hscale) 172e1001332Skettenis { 173e1001332Skettenis int src_w = drm_rect_width(src); 174e1001332Skettenis int dst_w = drm_rect_width(dst); 175e1001332Skettenis int hscale = drm_calc_scale(src_w, dst_w); 176e1001332Skettenis 177e1001332Skettenis if (hscale < 0 || dst_w == 0) 178e1001332Skettenis return hscale; 179e1001332Skettenis 180e1001332Skettenis if (hscale < min_hscale || hscale > max_hscale) 181e1001332Skettenis return -ERANGE; 182e1001332Skettenis 183e1001332Skettenis return hscale; 184e1001332Skettenis } 185e1001332Skettenis EXPORT_SYMBOL(drm_rect_calc_hscale); 186e1001332Skettenis 187e1001332Skettenis /** 188e1001332Skettenis * drm_rect_calc_vscale - calculate the vertical scaling factor 189e1001332Skettenis * @src: source window rectangle 190e1001332Skettenis * @dst: destination window rectangle 191e1001332Skettenis * @min_vscale: minimum allowed vertical scaling factor 192e1001332Skettenis * @max_vscale: maximum allowed vertical scaling factor 193e1001332Skettenis * 194e1001332Skettenis * Calculate the vertical scaling factor as 195e1001332Skettenis * (@src height) / (@dst height). 196e1001332Skettenis * 1977f4dd379Sjsg * If the scale is below 1 << 16, round down. If the scale is above 1987f4dd379Sjsg * 1 << 16, round up. This will calculate the scale with the most 1997f4dd379Sjsg * pessimistic limit calculation. 2007f4dd379Sjsg * 201e1001332Skettenis * RETURNS: 202e1001332Skettenis * The vertical scaling factor, or errno of out of limits. 203e1001332Skettenis */ 204e1001332Skettenis int drm_rect_calc_vscale(const struct drm_rect *src, 205e1001332Skettenis const struct drm_rect *dst, 206e1001332Skettenis int min_vscale, int max_vscale) 207e1001332Skettenis { 208e1001332Skettenis int src_h = drm_rect_height(src); 209e1001332Skettenis int dst_h = drm_rect_height(dst); 210e1001332Skettenis int vscale = drm_calc_scale(src_h, dst_h); 211e1001332Skettenis 212e1001332Skettenis if (vscale < 0 || dst_h == 0) 213e1001332Skettenis return vscale; 214e1001332Skettenis 215e1001332Skettenis if (vscale < min_vscale || vscale > max_vscale) 216e1001332Skettenis return -ERANGE; 217e1001332Skettenis 218e1001332Skettenis return vscale; 219e1001332Skettenis } 220e1001332Skettenis EXPORT_SYMBOL(drm_rect_calc_vscale); 221e1001332Skettenis 222e1001332Skettenis /** 223e1001332Skettenis * drm_rect_debug_print - print the rectangle information 2247f4dd379Sjsg * @prefix: prefix string 225e1001332Skettenis * @r: rectangle to print 226e1001332Skettenis * @fixed_point: rectangle is in 16.16 fixed point format 227e1001332Skettenis */ 2287f4dd379Sjsg void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) 229e1001332Skettenis { 230e1001332Skettenis if (fixed_point) 2317f4dd379Sjsg DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r)); 232e1001332Skettenis else 2337f4dd379Sjsg DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r)); 234e1001332Skettenis } 235e1001332Skettenis EXPORT_SYMBOL(drm_rect_debug_print); 2363253c27bSkettenis 2373253c27bSkettenis /** 2383253c27bSkettenis * drm_rect_rotate - Rotate the rectangle 2393253c27bSkettenis * @r: rectangle to be rotated 2403253c27bSkettenis * @width: Width of the coordinate space 2413253c27bSkettenis * @height: Height of the coordinate space 2423253c27bSkettenis * @rotation: Transformation to be applied 2433253c27bSkettenis * 2443253c27bSkettenis * Apply @rotation to the coordinates of rectangle @r. 2453253c27bSkettenis * 2463253c27bSkettenis * @width and @height combined with @rotation define 2473253c27bSkettenis * the location of the new origin. 2483253c27bSkettenis * 2493253c27bSkettenis * @width correcsponds to the horizontal and @height 2503253c27bSkettenis * to the vertical axis of the untransformed coordinate 2513253c27bSkettenis * space. 2523253c27bSkettenis */ 2533253c27bSkettenis void drm_rect_rotate(struct drm_rect *r, 2543253c27bSkettenis int width, int height, 2553253c27bSkettenis unsigned int rotation) 2563253c27bSkettenis { 2573253c27bSkettenis struct drm_rect tmp; 2583253c27bSkettenis 2597f4dd379Sjsg if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 2603253c27bSkettenis tmp = *r; 2613253c27bSkettenis 2627f4dd379Sjsg if (rotation & DRM_MODE_REFLECT_X) { 2633253c27bSkettenis r->x1 = width - tmp.x2; 2643253c27bSkettenis r->x2 = width - tmp.x1; 2653253c27bSkettenis } 2663253c27bSkettenis 2677f4dd379Sjsg if (rotation & DRM_MODE_REFLECT_Y) { 2683253c27bSkettenis r->y1 = height - tmp.y2; 2693253c27bSkettenis r->y2 = height - tmp.y1; 2703253c27bSkettenis } 2713253c27bSkettenis } 2723253c27bSkettenis 2737f4dd379Sjsg switch (rotation & DRM_MODE_ROTATE_MASK) { 2747f4dd379Sjsg case DRM_MODE_ROTATE_0: 2753253c27bSkettenis break; 2767f4dd379Sjsg case DRM_MODE_ROTATE_90: 2773253c27bSkettenis tmp = *r; 2783253c27bSkettenis r->x1 = tmp.y1; 2793253c27bSkettenis r->x2 = tmp.y2; 2803253c27bSkettenis r->y1 = width - tmp.x2; 2813253c27bSkettenis r->y2 = width - tmp.x1; 2823253c27bSkettenis break; 2837f4dd379Sjsg case DRM_MODE_ROTATE_180: 2843253c27bSkettenis tmp = *r; 2853253c27bSkettenis r->x1 = width - tmp.x2; 2863253c27bSkettenis r->x2 = width - tmp.x1; 2873253c27bSkettenis r->y1 = height - tmp.y2; 2883253c27bSkettenis r->y2 = height - tmp.y1; 2893253c27bSkettenis break; 2907f4dd379Sjsg case DRM_MODE_ROTATE_270: 2913253c27bSkettenis tmp = *r; 2923253c27bSkettenis r->x1 = height - tmp.y2; 2933253c27bSkettenis r->x2 = height - tmp.y1; 2943253c27bSkettenis r->y1 = tmp.x1; 2953253c27bSkettenis r->y2 = tmp.x2; 2963253c27bSkettenis break; 2973253c27bSkettenis default: 2983253c27bSkettenis break; 2993253c27bSkettenis } 3003253c27bSkettenis } 3013253c27bSkettenis EXPORT_SYMBOL(drm_rect_rotate); 3023253c27bSkettenis 3033253c27bSkettenis /** 3043253c27bSkettenis * drm_rect_rotate_inv - Inverse rotate the rectangle 3053253c27bSkettenis * @r: rectangle to be rotated 3063253c27bSkettenis * @width: Width of the coordinate space 3073253c27bSkettenis * @height: Height of the coordinate space 3083253c27bSkettenis * @rotation: Transformation whose inverse is to be applied 3093253c27bSkettenis * 3103253c27bSkettenis * Apply the inverse of @rotation to the coordinates 3113253c27bSkettenis * of rectangle @r. 3123253c27bSkettenis * 3133253c27bSkettenis * @width and @height combined with @rotation define 3143253c27bSkettenis * the location of the new origin. 3153253c27bSkettenis * 3163253c27bSkettenis * @width correcsponds to the horizontal and @height 3173253c27bSkettenis * to the vertical axis of the original untransformed 3183253c27bSkettenis * coordinate space, so that you never have to flip 3193253c27bSkettenis * them when doing a rotatation and its inverse. 3207f4dd379Sjsg * That is, if you do :: 3213253c27bSkettenis * 3227f4dd379Sjsg * drm_rect_rotate(&r, width, height, rotation); 3237f4dd379Sjsg * drm_rect_rotate_inv(&r, width, height, rotation); 3243253c27bSkettenis * 3253253c27bSkettenis * you will always get back the original rectangle. 3263253c27bSkettenis */ 3273253c27bSkettenis void drm_rect_rotate_inv(struct drm_rect *r, 3283253c27bSkettenis int width, int height, 3293253c27bSkettenis unsigned int rotation) 3303253c27bSkettenis { 3313253c27bSkettenis struct drm_rect tmp; 3323253c27bSkettenis 3337f4dd379Sjsg switch (rotation & DRM_MODE_ROTATE_MASK) { 3347f4dd379Sjsg case DRM_MODE_ROTATE_0: 3353253c27bSkettenis break; 3367f4dd379Sjsg case DRM_MODE_ROTATE_90: 3373253c27bSkettenis tmp = *r; 3383253c27bSkettenis r->x1 = width - tmp.y2; 3393253c27bSkettenis r->x2 = width - tmp.y1; 3403253c27bSkettenis r->y1 = tmp.x1; 3413253c27bSkettenis r->y2 = tmp.x2; 3423253c27bSkettenis break; 3437f4dd379Sjsg case DRM_MODE_ROTATE_180: 3443253c27bSkettenis tmp = *r; 3453253c27bSkettenis r->x1 = width - tmp.x2; 3463253c27bSkettenis r->x2 = width - tmp.x1; 3473253c27bSkettenis r->y1 = height - tmp.y2; 3483253c27bSkettenis r->y2 = height - tmp.y1; 3493253c27bSkettenis break; 3507f4dd379Sjsg case DRM_MODE_ROTATE_270: 3513253c27bSkettenis tmp = *r; 3523253c27bSkettenis r->x1 = tmp.y1; 3533253c27bSkettenis r->x2 = tmp.y2; 3543253c27bSkettenis r->y1 = height - tmp.x2; 3553253c27bSkettenis r->y2 = height - tmp.x1; 3563253c27bSkettenis break; 3573253c27bSkettenis default: 3583253c27bSkettenis break; 3593253c27bSkettenis } 3603253c27bSkettenis 3617f4dd379Sjsg if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 3623253c27bSkettenis tmp = *r; 3633253c27bSkettenis 3647f4dd379Sjsg if (rotation & DRM_MODE_REFLECT_X) { 3653253c27bSkettenis r->x1 = width - tmp.x2; 3663253c27bSkettenis r->x2 = width - tmp.x1; 3673253c27bSkettenis } 3683253c27bSkettenis 3697f4dd379Sjsg if (rotation & DRM_MODE_REFLECT_Y) { 3703253c27bSkettenis r->y1 = height - tmp.y2; 3713253c27bSkettenis r->y2 = height - tmp.y1; 3723253c27bSkettenis } 3733253c27bSkettenis } 3743253c27bSkettenis } 3753253c27bSkettenis EXPORT_SYMBOL(drm_rect_rotate_inv); 376