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 (WARN_ON(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        if (fixed_point)
 285                DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r));
 286        else
 287                DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r));
 288}
 289EXPORT_SYMBOL(drm_rect_debug_print);
 290
 291/**
 292 * drm_rect_rotate - 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 to be applied
 297 *
 298 * Apply @rotation to the coordinates of rectangle @r.
 299 *
 300 * @width and @height combined with @rotation define
 301 * the location of the new origin.
 302 *
 303 * @width correcsponds to the horizontal and @height
 304 * to the vertical axis of the untransformed coordinate
 305 * space.
 306 */
 307void drm_rect_rotate(struct drm_rect *r,
 308                     int width, int height,
 309                     unsigned int rotation)
 310{
 311        struct drm_rect tmp;
 312
 313        if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
 314                tmp = *r;
 315
 316                if (rotation & DRM_MODE_REFLECT_X) {
 317                        r->x1 = width - tmp.x2;
 318                        r->x2 = width - tmp.x1;
 319                }
 320
 321                if (rotation & DRM_MODE_REFLECT_Y) {
 322                        r->y1 = height - tmp.y2;
 323                        r->y2 = height - tmp.y1;
 324                }
 325        }
 326
 327        switch (rotation & DRM_MODE_ROTATE_MASK) {
 328        case DRM_MODE_ROTATE_0:
 329                break;
 330        case DRM_MODE_ROTATE_90:
 331                tmp = *r;
 332                r->x1 = tmp.y1;
 333                r->x2 = tmp.y2;
 334                r->y1 = width - tmp.x2;
 335                r->y2 = width - tmp.x1;
 336                break;
 337        case DRM_MODE_ROTATE_180:
 338                tmp = *r;
 339                r->x1 = width - tmp.x2;
 340                r->x2 = width - tmp.x1;
 341                r->y1 = height - tmp.y2;
 342                r->y2 = height - tmp.y1;
 343                break;
 344        case DRM_MODE_ROTATE_270:
 345                tmp = *r;
 346                r->x1 = height - tmp.y2;
 347                r->x2 = height - tmp.y1;
 348                r->y1 = tmp.x1;
 349                r->y2 = tmp.x2;
 350                break;
 351        default:
 352                break;
 353        }
 354}
 355EXPORT_SYMBOL(drm_rect_rotate);
 356
 357/**
 358 * drm_rect_rotate_inv - Inverse rotate the rectangle
 359 * @r: rectangle to be rotated
 360 * @width: Width of the coordinate space
 361 * @height: Height of the coordinate space
 362 * @rotation: Transformation whose inverse is to be applied
 363 *
 364 * Apply the inverse of @rotation to the coordinates
 365 * of rectangle @r.
 366 *
 367 * @width and @height combined with @rotation define
 368 * the location of the new origin.
 369 *
 370 * @width correcsponds to the horizontal and @height
 371 * to the vertical axis of the original untransformed
 372 * coordinate space, so that you never have to flip
 373 * them when doing a rotatation and its inverse.
 374 * That is, if you do ::
 375 *
 376 *     DRM_MODE_PROP_ROTATE(&r, width, height, rotation);
 377 *     DRM_MODE_ROTATE_inv(&r, width, height, rotation);
 378 *
 379 * you will always get back the original rectangle.
 380 */
 381void drm_rect_rotate_inv(struct drm_rect *r,
 382                         int width, int height,
 383                         unsigned int rotation)
 384{
 385        struct drm_rect tmp;
 386
 387        switch (rotation & DRM_MODE_ROTATE_MASK) {
 388        case DRM_MODE_ROTATE_0:
 389                break;
 390        case DRM_MODE_ROTATE_90:
 391                tmp = *r;
 392                r->x1 = width - tmp.y2;
 393                r->x2 = width - tmp.y1;
 394                r->y1 = tmp.x1;
 395                r->y2 = tmp.x2;
 396                break;
 397        case DRM_MODE_ROTATE_180:
 398                tmp = *r;
 399                r->x1 = width - tmp.x2;
 400                r->x2 = width - tmp.x1;
 401                r->y1 = height - tmp.y2;
 402                r->y2 = height - tmp.y1;
 403                break;
 404        case DRM_MODE_ROTATE_270:
 405                tmp = *r;
 406                r->x1 = tmp.y1;
 407                r->x2 = tmp.y2;
 408                r->y1 = height - tmp.x2;
 409                r->y2 = height - tmp.x1;
 410                break;
 411        default:
 412                break;
 413        }
 414
 415        if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
 416                tmp = *r;
 417
 418                if (rotation & DRM_MODE_REFLECT_X) {
 419                        r->x1 = width - tmp.x2;
 420                        r->x2 = width - tmp.x1;
 421                }
 422
 423                if (rotation & DRM_MODE_REFLECT_Y) {
 424                        r->y1 = height - tmp.y2;
 425                        r->y2 = height - tmp.y1;
 426                }
 427        }
 428}
 429EXPORT_SYMBOL(drm_rect_rotate_inv);
 430