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