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_calc_hscale_relaxed - calculate the horizontal scaling factor 212 * @src: source window rectangle 213 * @dst: destination window rectangle 214 * @min_hscale: minimum allowed horizontal scaling factor 215 * @max_hscale: maximum allowed horizontal scaling factor 216 * 217 * Calculate the horizontal scaling factor as 218 * (@src width) / (@dst width). 219 * 220 * If the calculated scaling factor is below @min_vscale, 221 * decrease the height of rectangle @dst to compensate. 222 * 223 * If the calculated scaling factor is above @max_vscale, 224 * decrease the height of rectangle @src to compensate. 225 * 226 * If the scale is below 1 << 16, round down. If the scale is above 227 * 1 << 16, round up. This will calculate the scale with the most 228 * pessimistic limit calculation. 229 * 230 * RETURNS: 231 * The horizontal scaling factor. 232 */ 233 int drm_rect_calc_hscale_relaxed(struct drm_rect *src, 234 struct drm_rect *dst, 235 int min_hscale, int max_hscale) 236 { 237 int src_w = drm_rect_width(src); 238 int dst_w = drm_rect_width(dst); 239 int hscale = drm_calc_scale(src_w, dst_w); 240 241 if (hscale < 0 || dst_w == 0) 242 return hscale; 243 244 if (hscale < min_hscale) { 245 int max_dst_w = src_w / min_hscale; 246 247 drm_rect_adjust_size(dst, max_dst_w - dst_w, 0); 248 249 return min_hscale; 250 } 251 252 if (hscale > max_hscale) { 253 int max_src_w = dst_w * max_hscale; 254 255 drm_rect_adjust_size(src, max_src_w - src_w, 0); 256 257 return max_hscale; 258 } 259 260 return hscale; 261 } 262 EXPORT_SYMBOL(drm_rect_calc_hscale_relaxed); 263 264 /** 265 * drm_rect_calc_vscale_relaxed - calculate the vertical scaling factor 266 * @src: source window rectangle 267 * @dst: destination window rectangle 268 * @min_vscale: minimum allowed vertical scaling factor 269 * @max_vscale: maximum allowed vertical scaling factor 270 * 271 * Calculate the vertical scaling factor as 272 * (@src height) / (@dst height). 273 * 274 * If the calculated scaling factor is below @min_vscale, 275 * decrease the height of rectangle @dst to compensate. 276 * 277 * If the calculated scaling factor is above @max_vscale, 278 * decrease the height of rectangle @src to compensate. 279 * 280 * If the scale is below 1 << 16, round down. If the scale is above 281 * 1 << 16, round up. This will calculate the scale with the most 282 * pessimistic limit calculation. 283 * 284 * RETURNS: 285 * The vertical scaling factor. 286 */ 287 int drm_rect_calc_vscale_relaxed(struct drm_rect *src, 288 struct drm_rect *dst, 289 int min_vscale, int max_vscale) 290 { 291 int src_h = drm_rect_height(src); 292 int dst_h = drm_rect_height(dst); 293 int vscale = drm_calc_scale(src_h, dst_h); 294 295 if (vscale < 0 || dst_h == 0) 296 return vscale; 297 298 if (vscale < min_vscale) { 299 int max_dst_h = src_h / min_vscale; 300 301 drm_rect_adjust_size(dst, 0, max_dst_h - dst_h); 302 303 return min_vscale; 304 } 305 306 if (vscale > max_vscale) { 307 int max_src_h = dst_h * max_vscale; 308 309 drm_rect_adjust_size(src, 0, max_src_h - src_h); 310 311 return max_vscale; 312 } 313 314 return vscale; 315 } 316 EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed); 317 318 /** 319 * drm_rect_debug_print - print the rectangle information 320 * @prefix: prefix string 321 * @r: rectangle to print 322 * @fixed_point: rectangle is in 16.16 fixed point format 323 */ 324 void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) 325 { 326 if (fixed_point) 327 DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r)); 328 else 329 DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r)); 330 } 331 EXPORT_SYMBOL(drm_rect_debug_print); 332 333 /** 334 * drm_rect_rotate - Rotate the rectangle 335 * @r: rectangle to be rotated 336 * @width: Width of the coordinate space 337 * @height: Height of the coordinate space 338 * @rotation: Transformation to be applied 339 * 340 * Apply @rotation to the coordinates of rectangle @r. 341 * 342 * @width and @height combined with @rotation define 343 * the location of the new origin. 344 * 345 * @width correcsponds to the horizontal and @height 346 * to the vertical axis of the untransformed coordinate 347 * space. 348 */ 349 void drm_rect_rotate(struct drm_rect *r, 350 int width, int height, 351 unsigned int rotation) 352 { 353 struct drm_rect tmp; 354 355 if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 356 tmp = *r; 357 358 if (rotation & DRM_MODE_REFLECT_X) { 359 r->x1 = width - tmp.x2; 360 r->x2 = width - tmp.x1; 361 } 362 363 if (rotation & DRM_MODE_REFLECT_Y) { 364 r->y1 = height - tmp.y2; 365 r->y2 = height - tmp.y1; 366 } 367 } 368 369 switch (rotation & DRM_MODE_ROTATE_MASK) { 370 case DRM_MODE_ROTATE_0: 371 break; 372 case DRM_MODE_ROTATE_90: 373 tmp = *r; 374 r->x1 = tmp.y1; 375 r->x2 = tmp.y2; 376 r->y1 = width - tmp.x2; 377 r->y2 = width - tmp.x1; 378 break; 379 case DRM_MODE_ROTATE_180: 380 tmp = *r; 381 r->x1 = width - tmp.x2; 382 r->x2 = width - tmp.x1; 383 r->y1 = height - tmp.y2; 384 r->y2 = height - tmp.y1; 385 break; 386 case DRM_MODE_ROTATE_270: 387 tmp = *r; 388 r->x1 = height - tmp.y2; 389 r->x2 = height - tmp.y1; 390 r->y1 = tmp.x1; 391 r->y2 = tmp.x2; 392 break; 393 default: 394 break; 395 } 396 } 397 EXPORT_SYMBOL(drm_rect_rotate); 398 399 /** 400 * drm_rect_rotate_inv - Inverse rotate the rectangle 401 * @r: rectangle to be rotated 402 * @width: Width of the coordinate space 403 * @height: Height of the coordinate space 404 * @rotation: Transformation whose inverse is to be applied 405 * 406 * Apply the inverse of @rotation to the coordinates 407 * of rectangle @r. 408 * 409 * @width and @height combined with @rotation define 410 * the location of the new origin. 411 * 412 * @width correcsponds to the horizontal and @height 413 * to the vertical axis of the original untransformed 414 * coordinate space, so that you never have to flip 415 * them when doing a rotatation and its inverse. 416 * That is, if you do :: 417 * 418 * drm_rect_rotate(&r, width, height, rotation); 419 * drm_rect_rotate_inv(&r, width, height, rotation); 420 * 421 * you will always get back the original rectangle. 422 */ 423 void drm_rect_rotate_inv(struct drm_rect *r, 424 int width, int height, 425 unsigned int rotation) 426 { 427 struct drm_rect tmp; 428 429 switch (rotation & DRM_MODE_ROTATE_MASK) { 430 case DRM_MODE_ROTATE_0: 431 break; 432 case DRM_MODE_ROTATE_90: 433 tmp = *r; 434 r->x1 = width - tmp.y2; 435 r->x2 = width - tmp.y1; 436 r->y1 = tmp.x1; 437 r->y2 = tmp.x2; 438 break; 439 case DRM_MODE_ROTATE_180: 440 tmp = *r; 441 r->x1 = width - tmp.x2; 442 r->x2 = width - tmp.x1; 443 r->y1 = height - tmp.y2; 444 r->y2 = height - tmp.y1; 445 break; 446 case DRM_MODE_ROTATE_270: 447 tmp = *r; 448 r->x1 = tmp.y1; 449 r->x2 = tmp.y2; 450 r->y1 = height - tmp.x2; 451 r->y2 = height - tmp.x1; 452 break; 453 default: 454 break; 455 } 456 457 if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) { 458 tmp = *r; 459 460 if (rotation & DRM_MODE_REFLECT_X) { 461 r->x1 = width - tmp.x2; 462 r->x2 = width - tmp.x1; 463 } 464 465 if (rotation & DRM_MODE_REFLECT_Y) { 466 r->y1 = height - tmp.y2; 467 r->y2 = height - tmp.y1; 468 } 469 } 470 } 471 EXPORT_SYMBOL(drm_rect_rotate_inv); 472