1 /* 2 * Copyright (C) 2011-2013 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24 #include <linux/errno.h> 25 #include <linux/export.h> 26 #include <linux/kernel.h> 27 #include <drm/drmP.h> 28 #include <drm/drm_rect.h> 29 30 /** 31 * drm_rect_intersect - intersect two rectangles 32 * @r1: first rectangle 33 * @r2: second rectangle 34 * 35 * Calculate the intersection of rectangles @r1 and @r2. 36 * @r1 will be overwritten with the intersection. 37 * 38 * RETURNS: 39 * %true if rectangle @r1 is still visible after the operation, 40 * %false otherwise. 41 */ 42 bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2) 43 { 44 r1->x1 = max(r1->x1, r2->x1); 45 r1->y1 = max(r1->y1, r2->y1); 46 r1->x2 = min(r1->x2, r2->x2); 47 r1->y2 = min(r1->y2, r2->y2); 48 49 return drm_rect_visible(r1); 50 } 51 EXPORT_SYMBOL(drm_rect_intersect); 52 53 static u32 clip_scaled(u32 src, u32 dst, u32 clip) 54 { 55 u64 tmp = mul_u32_u32(src, dst - clip); 56 57 /* 58 * Round toward 1.0 when clipping so that we don't accidentally 59 * change upscaling to downscaling or vice versa. 60 */ 61 if (src < (dst << 16)) 62 return DIV_ROUND_UP_ULL(tmp, dst); 63 else 64 return DIV_ROUND_DOWN_ULL(tmp, dst); 65 } 66 67 /** 68 * drm_rect_clip_scaled - perform a scaled clip operation 69 * @src: source window rectangle 70 * @dst: destination window rectangle 71 * @clip: clip rectangle 72 * 73 * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the 74 * same amounts multiplied by @hscale and @vscale. 75 * 76 * RETURNS: 77 * %true if rectangle @dst is still visible after being clipped, 78 * %false otherwise 79 */ 80 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 81 const struct drm_rect *clip) 82 { 83 int diff; 84 85 diff = clip->x1 - dst->x1; 86 if (diff > 0) { 87 u32 new_src_w = clip_scaled(drm_rect_width(src), 88 drm_rect_width(dst), diff); 89 90 src->x1 = clamp_t(int64_t, src->x2 - new_src_w, INT_MIN, INT_MAX); 91 dst->x1 = clip->x1; 92 } 93 diff = clip->y1 - dst->y1; 94 if (diff > 0) { 95 u32 new_src_h = clip_scaled(drm_rect_height(src), 96 drm_rect_height(dst), diff); 97 98 src->y1 = clamp_t(int64_t, src->y2 - new_src_h, INT_MIN, INT_MAX); 99 dst->y1 = clip->y1; 100 } 101 diff = dst->x2 - clip->x2; 102 if (diff > 0) { 103 u32 new_src_w = clip_scaled(drm_rect_width(src), 104 drm_rect_width(dst), diff); 105 106 src->x2 = clamp_t(int64_t, src->x1 + new_src_w, INT_MIN, INT_MAX); 107 dst->x2 = clip->x2; 108 } 109 diff = dst->y2 - clip->y2; 110 if (diff > 0) { 111 u32 new_src_h = clip_scaled(drm_rect_height(src), 112 drm_rect_height(dst), diff); 113 114 src->y2 = clamp_t(int64_t, src->y1 + new_src_h, INT_MIN, INT_MAX); 115 dst->y2 = clip->y2; 116 } 117 118 return drm_rect_visible(dst); 119 } 120 EXPORT_SYMBOL(drm_rect_clip_scaled); 121 122 static int drm_calc_scale(int src, int dst) 123 { 124 int scale = 0; 125 126 if (WARN_ON(src < 0 || dst < 0)) 127 return -EINVAL; 128 129 if (dst == 0) 130 return 0; 131 132 if (src > (dst << 16)) 133 return DIV_ROUND_UP(src, dst); 134 else 135 scale = src / dst; 136 137 return scale; 138 } 139 140 /** 141 * drm_rect_calc_hscale - calculate the horizontal scaling factor 142 * @src: source window rectangle 143 * @dst: destination window rectangle 144 * @min_hscale: minimum allowed horizontal scaling factor 145 * @max_hscale: maximum allowed horizontal scaling factor 146 * 147 * Calculate the horizontal scaling factor as 148 * (@src width) / (@dst width). 149 * 150 * If the scale is below 1 << 16, round down. If the scale is above 151 * 1 << 16, round up. This will calculate the scale with the most 152 * pessimistic limit calculation. 153 * 154 * RETURNS: 155 * The horizontal scaling factor, or errno of out of limits. 156 */ 157 int drm_rect_calc_hscale(const struct drm_rect *src, 158 const struct drm_rect *dst, 159 int min_hscale, int max_hscale) 160 { 161 int src_w = drm_rect_width(src); 162 int dst_w = drm_rect_width(dst); 163 int hscale = drm_calc_scale(src_w, dst_w); 164 165 if (hscale < 0 || dst_w == 0) 166 return hscale; 167 168 if (hscale < min_hscale || hscale > max_hscale) 169 return -ERANGE; 170 171 return hscale; 172 } 173 EXPORT_SYMBOL(drm_rect_calc_hscale); 174 175 /** 176 * drm_rect_calc_vscale - calculate the vertical scaling factor 177 * @src: source window rectangle 178 * @dst: destination window rectangle 179 * @min_vscale: minimum allowed vertical scaling factor 180 * @max_vscale: maximum allowed vertical scaling factor 181 * 182 * Calculate the vertical scaling factor as 183 * (@src height) / (@dst height). 184 * 185 * If the scale is below 1 << 16, round down. If the scale is above 186 * 1 << 16, round up. This will calculate the scale with the most 187 * pessimistic limit calculation. 188 * 189 * RETURNS: 190 * The vertical scaling factor, or errno of out of limits. 191 */ 192 int drm_rect_calc_vscale(const struct drm_rect *src, 193 const struct drm_rect *dst, 194 int min_vscale, int max_vscale) 195 { 196 int src_h = drm_rect_height(src); 197 int dst_h = drm_rect_height(dst); 198 int vscale = drm_calc_scale(src_h, dst_h); 199 200 if (vscale < 0 || dst_h == 0) 201 return vscale; 202 203 if (vscale < min_vscale || vscale > max_vscale) 204 return -ERANGE; 205 206 return vscale; 207 } 208 EXPORT_SYMBOL(drm_rect_calc_vscale); 209 210 /** 211 * drm_rect_debug_print - print the rectangle information 212 * @prefix: prefix string 213 * @r: rectangle to print 214 * @fixed_point: rectangle is in 16.16 fixed point format 215 */ 216 void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) 217 { 218 if (fixed_point) 219 DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r)); 220 else 221 DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r)); 222 } 223 EXPORT_SYMBOL(drm_rect_debug_print); 224 225 /** 226 * drm_rect_rotate - Rotate the rectangle 227 * @r: rectangle to be rotated 228 * @width: Width of the coordinate space 229 * @height: Height of the coordinate space 230 * @rotation: Transformation to be applied 231 * 232 * Apply @rotation to the coordinates of rectangle @r. 233 * 234 * @width and @height combined with @rotation define 235 * the location of the new origin. 236 * 237 * @width correcsponds to the horizontal and @height 238 * to the vertical axis of the untransformed coordinate 239 * space. 240 */ 241 void drm_rect_rotate(struct drm_rect *r, 242 int width, int height, 243 unsigned int rotation) 244 { 245 struct drm_rect tmp; 246 247 if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 248 tmp = *r; 249 250 if (rotation & DRM_MODE_REFLECT_X) { 251 r->x1 = width - tmp.x2; 252 r->x2 = width - tmp.x1; 253 } 254 255 if (rotation & DRM_MODE_REFLECT_Y) { 256 r->y1 = height - tmp.y2; 257 r->y2 = height - tmp.y1; 258 } 259 } 260 261 switch (rotation & DRM_MODE_ROTATE_MASK) { 262 case DRM_MODE_ROTATE_0: 263 break; 264 case DRM_MODE_ROTATE_90: 265 tmp = *r; 266 r->x1 = tmp.y1; 267 r->x2 = tmp.y2; 268 r->y1 = width - tmp.x2; 269 r->y2 = width - tmp.x1; 270 break; 271 case DRM_MODE_ROTATE_180: 272 tmp = *r; 273 r->x1 = width - tmp.x2; 274 r->x2 = width - tmp.x1; 275 r->y1 = height - tmp.y2; 276 r->y2 = height - tmp.y1; 277 break; 278 case DRM_MODE_ROTATE_270: 279 tmp = *r; 280 r->x1 = height - tmp.y2; 281 r->x2 = height - tmp.y1; 282 r->y1 = tmp.x1; 283 r->y2 = tmp.x2; 284 break; 285 default: 286 break; 287 } 288 } 289 EXPORT_SYMBOL(drm_rect_rotate); 290 291 /** 292 * drm_rect_rotate_inv - Inverse rotate the rectangle 293 * @r: rectangle to be rotated 294 * @width: Width of the coordinate space 295 * @height: Height of the coordinate space 296 * @rotation: Transformation whose inverse is to be applied 297 * 298 * Apply the inverse of @rotation to the coordinates 299 * of rectangle @r. 300 * 301 * @width and @height combined with @rotation define 302 * the location of the new origin. 303 * 304 * @width correcsponds to the horizontal and @height 305 * to the vertical axis of the original untransformed 306 * coordinate space, so that you never have to flip 307 * them when doing a rotatation and its inverse. 308 * That is, if you do :: 309 * 310 * drm_rect_rotate(&r, width, height, rotation); 311 * drm_rect_rotate_inv(&r, width, height, rotation); 312 * 313 * you will always get back the original rectangle. 314 */ 315 void drm_rect_rotate_inv(struct drm_rect *r, 316 int width, int height, 317 unsigned int rotation) 318 { 319 struct drm_rect tmp; 320 321 switch (rotation & DRM_MODE_ROTATE_MASK) { 322 case DRM_MODE_ROTATE_0: 323 break; 324 case DRM_MODE_ROTATE_90: 325 tmp = *r; 326 r->x1 = width - tmp.y2; 327 r->x2 = width - tmp.y1; 328 r->y1 = tmp.x1; 329 r->y2 = tmp.x2; 330 break; 331 case DRM_MODE_ROTATE_180: 332 tmp = *r; 333 r->x1 = width - tmp.x2; 334 r->x2 = width - tmp.x1; 335 r->y1 = height - tmp.y2; 336 r->y2 = height - tmp.y1; 337 break; 338 case DRM_MODE_ROTATE_270: 339 tmp = *r; 340 r->x1 = tmp.y1; 341 r->x2 = tmp.y2; 342 r->y1 = height - tmp.x2; 343 r->y2 = height - tmp.x1; 344 break; 345 default: 346 break; 347 } 348 349 if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 350 tmp = *r; 351 352 if (rotation & DRM_MODE_REFLECT_X) { 353 r->x1 = width - tmp.x2; 354 r->x2 = width - tmp.x1; 355 } 356 357 if (rotation & DRM_MODE_REFLECT_Y) { 358 r->y1 = height - tmp.y2; 359 r->y2 = height - tmp.y1; 360 } 361 } 362 } 363 EXPORT_SYMBOL(drm_rect_rotate_inv); 364