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