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