Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2011-2013 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0021  * SOFTWARE.
0022  */
0023 
0024 #include <linux/errno.h>
0025 #include <linux/export.h>
0026 #include <linux/kernel.h>
0027 
0028 #include <drm/drm_mode.h>
0029 #include <drm/drm_print.h>
0030 #include <drm/drm_rect.h>
0031 
0032 /**
0033  * drm_rect_intersect - intersect two rectangles
0034  * @r1: first rectangle
0035  * @r2: second rectangle
0036  *
0037  * Calculate the intersection of rectangles @r1 and @r2.
0038  * @r1 will be overwritten with the intersection.
0039  *
0040  * RETURNS:
0041  * %true if rectangle @r1 is still visible after the operation,
0042  * %false otherwise.
0043  */
0044 bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
0045 {
0046     r1->x1 = max(r1->x1, r2->x1);
0047     r1->y1 = max(r1->y1, r2->y1);
0048     r1->x2 = min(r1->x2, r2->x2);
0049     r1->y2 = min(r1->y2, r2->y2);
0050 
0051     return drm_rect_visible(r1);
0052 }
0053 EXPORT_SYMBOL(drm_rect_intersect);
0054 
0055 static u32 clip_scaled(int src, int dst, int *clip)
0056 {
0057     u64 tmp;
0058 
0059     if (dst == 0)
0060         return 0;
0061 
0062     /* Only clip what we have. Keeps the result bounded. */
0063     *clip = min(*clip, dst);
0064 
0065     tmp = mul_u32_u32(src, dst - *clip);
0066 
0067     /*
0068      * Round toward 1.0 when clipping so that we don't accidentally
0069      * change upscaling to downscaling or vice versa.
0070      */
0071     if (src < (dst << 16))
0072         return DIV_ROUND_UP_ULL(tmp, dst);
0073     else
0074         return DIV_ROUND_DOWN_ULL(tmp, dst);
0075 }
0076 
0077 /**
0078  * drm_rect_clip_scaled - perform a scaled clip operation
0079  * @src: source window rectangle
0080  * @dst: destination window rectangle
0081  * @clip: clip rectangle
0082  *
0083  * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
0084  * the corresponding amounts, retaining the vertical and horizontal scaling
0085  * factors from @src to @dst.
0086  *
0087  * RETURNS:
0088  *
0089  * %true if rectangle @dst is still visible after being clipped,
0090  * %false otherwise.
0091  */
0092 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
0093               const struct drm_rect *clip)
0094 {
0095     int diff;
0096 
0097     diff = clip->x1 - dst->x1;
0098     if (diff > 0) {
0099         u32 new_src_w = clip_scaled(drm_rect_width(src),
0100                         drm_rect_width(dst), &diff);
0101 
0102         src->x1 = src->x2 - new_src_w;
0103         dst->x1 += diff;
0104     }
0105     diff = clip->y1 - dst->y1;
0106     if (diff > 0) {
0107         u32 new_src_h = clip_scaled(drm_rect_height(src),
0108                         drm_rect_height(dst), &diff);
0109 
0110         src->y1 = src->y2 - new_src_h;
0111         dst->y1 += diff;
0112     }
0113     diff = dst->x2 - clip->x2;
0114     if (diff > 0) {
0115         u32 new_src_w = clip_scaled(drm_rect_width(src),
0116                         drm_rect_width(dst), &diff);
0117 
0118         src->x2 = src->x1 + new_src_w;
0119         dst->x2 -= diff;
0120     }
0121     diff = dst->y2 - clip->y2;
0122     if (diff > 0) {
0123         u32 new_src_h = clip_scaled(drm_rect_height(src),
0124                         drm_rect_height(dst), &diff);
0125 
0126         src->y2 = src->y1 + new_src_h;
0127         dst->y2 -= diff;
0128     }
0129 
0130     return drm_rect_visible(dst);
0131 }
0132 EXPORT_SYMBOL(drm_rect_clip_scaled);
0133 
0134 static int drm_calc_scale(int src, int dst)
0135 {
0136     int scale = 0;
0137 
0138     if (WARN_ON(src < 0 || dst < 0))
0139         return -EINVAL;
0140 
0141     if (dst == 0)
0142         return 0;
0143 
0144     if (src > (dst << 16))
0145         return DIV_ROUND_UP(src, dst);
0146     else
0147         scale = src / dst;
0148 
0149     return scale;
0150 }
0151 
0152 /**
0153  * drm_rect_calc_hscale - calculate the horizontal scaling factor
0154  * @src: source window rectangle
0155  * @dst: destination window rectangle
0156  * @min_hscale: minimum allowed horizontal scaling factor
0157  * @max_hscale: maximum allowed horizontal scaling factor
0158  *
0159  * Calculate the horizontal scaling factor as
0160  * (@src width) / (@dst width).
0161  *
0162  * If the scale is below 1 << 16, round down. If the scale is above
0163  * 1 << 16, round up. This will calculate the scale with the most
0164  * pessimistic limit calculation.
0165  *
0166  * RETURNS:
0167  * The horizontal scaling factor, or errno of out of limits.
0168  */
0169 int drm_rect_calc_hscale(const struct drm_rect *src,
0170              const struct drm_rect *dst,
0171              int min_hscale, int max_hscale)
0172 {
0173     int src_w = drm_rect_width(src);
0174     int dst_w = drm_rect_width(dst);
0175     int hscale = drm_calc_scale(src_w, dst_w);
0176 
0177     if (hscale < 0 || dst_w == 0)
0178         return hscale;
0179 
0180     if (hscale < min_hscale || hscale > max_hscale)
0181         return -ERANGE;
0182 
0183     return hscale;
0184 }
0185 EXPORT_SYMBOL(drm_rect_calc_hscale);
0186 
0187 /**
0188  * drm_rect_calc_vscale - calculate the vertical scaling factor
0189  * @src: source window rectangle
0190  * @dst: destination window rectangle
0191  * @min_vscale: minimum allowed vertical scaling factor
0192  * @max_vscale: maximum allowed vertical scaling factor
0193  *
0194  * Calculate the vertical scaling factor as
0195  * (@src height) / (@dst height).
0196  *
0197  * If the scale is below 1 << 16, round down. If the scale is above
0198  * 1 << 16, round up. This will calculate the scale with the most
0199  * pessimistic limit calculation.
0200  *
0201  * RETURNS:
0202  * The vertical scaling factor, or errno of out of limits.
0203  */
0204 int drm_rect_calc_vscale(const struct drm_rect *src,
0205              const struct drm_rect *dst,
0206              int min_vscale, int max_vscale)
0207 {
0208     int src_h = drm_rect_height(src);
0209     int dst_h = drm_rect_height(dst);
0210     int vscale = drm_calc_scale(src_h, dst_h);
0211 
0212     if (vscale < 0 || dst_h == 0)
0213         return vscale;
0214 
0215     if (vscale < min_vscale || vscale > max_vscale)
0216         return -ERANGE;
0217 
0218     return vscale;
0219 }
0220 EXPORT_SYMBOL(drm_rect_calc_vscale);
0221 
0222 /**
0223  * drm_rect_debug_print - print the rectangle information
0224  * @prefix: prefix string
0225  * @r: rectangle to print
0226  * @fixed_point: rectangle is in 16.16 fixed point format
0227  */
0228 void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
0229 {
0230     if (fixed_point)
0231         DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r));
0232     else
0233         DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r));
0234 }
0235 EXPORT_SYMBOL(drm_rect_debug_print);
0236 
0237 /**
0238  * drm_rect_rotate - Rotate the rectangle
0239  * @r: rectangle to be rotated
0240  * @width: Width of the coordinate space
0241  * @height: Height of the coordinate space
0242  * @rotation: Transformation to be applied
0243  *
0244  * Apply @rotation to the coordinates of rectangle @r.
0245  *
0246  * @width and @height combined with @rotation define
0247  * the location of the new origin.
0248  *
0249  * @width correcsponds to the horizontal and @height
0250  * to the vertical axis of the untransformed coordinate
0251  * space.
0252  */
0253 void drm_rect_rotate(struct drm_rect *r,
0254              int width, int height,
0255              unsigned int rotation)
0256 {
0257     struct drm_rect tmp;
0258 
0259     if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
0260         tmp = *r;
0261 
0262         if (rotation & DRM_MODE_REFLECT_X) {
0263             r->x1 = width - tmp.x2;
0264             r->x2 = width - tmp.x1;
0265         }
0266 
0267         if (rotation & DRM_MODE_REFLECT_Y) {
0268             r->y1 = height - tmp.y2;
0269             r->y2 = height - tmp.y1;
0270         }
0271     }
0272 
0273     switch (rotation & DRM_MODE_ROTATE_MASK) {
0274     case DRM_MODE_ROTATE_0:
0275         break;
0276     case DRM_MODE_ROTATE_90:
0277         tmp = *r;
0278         r->x1 = tmp.y1;
0279         r->x2 = tmp.y2;
0280         r->y1 = width - tmp.x2;
0281         r->y2 = width - tmp.x1;
0282         break;
0283     case DRM_MODE_ROTATE_180:
0284         tmp = *r;
0285         r->x1 = width - tmp.x2;
0286         r->x2 = width - tmp.x1;
0287         r->y1 = height - tmp.y2;
0288         r->y2 = height - tmp.y1;
0289         break;
0290     case DRM_MODE_ROTATE_270:
0291         tmp = *r;
0292         r->x1 = height - tmp.y2;
0293         r->x2 = height - tmp.y1;
0294         r->y1 = tmp.x1;
0295         r->y2 = tmp.x2;
0296         break;
0297     default:
0298         break;
0299     }
0300 }
0301 EXPORT_SYMBOL(drm_rect_rotate);
0302 
0303 /**
0304  * drm_rect_rotate_inv - Inverse rotate the rectangle
0305  * @r: rectangle to be rotated
0306  * @width: Width of the coordinate space
0307  * @height: Height of the coordinate space
0308  * @rotation: Transformation whose inverse is to be applied
0309  *
0310  * Apply the inverse of @rotation to the coordinates
0311  * of rectangle @r.
0312  *
0313  * @width and @height combined with @rotation define
0314  * the location of the new origin.
0315  *
0316  * @width correcsponds to the horizontal and @height
0317  * to the vertical axis of the original untransformed
0318  * coordinate space, so that you never have to flip
0319  * them when doing a rotatation and its inverse.
0320  * That is, if you do ::
0321  *
0322  *     drm_rect_rotate(&r, width, height, rotation);
0323  *     drm_rect_rotate_inv(&r, width, height, rotation);
0324  *
0325  * you will always get back the original rectangle.
0326  */
0327 void drm_rect_rotate_inv(struct drm_rect *r,
0328              int width, int height,
0329              unsigned int rotation)
0330 {
0331     struct drm_rect tmp;
0332 
0333     switch (rotation & DRM_MODE_ROTATE_MASK) {
0334     case DRM_MODE_ROTATE_0:
0335         break;
0336     case DRM_MODE_ROTATE_90:
0337         tmp = *r;
0338         r->x1 = width - tmp.y2;
0339         r->x2 = width - tmp.y1;
0340         r->y1 = tmp.x1;
0341         r->y2 = tmp.x2;
0342         break;
0343     case DRM_MODE_ROTATE_180:
0344         tmp = *r;
0345         r->x1 = width - tmp.x2;
0346         r->x2 = width - tmp.x1;
0347         r->y1 = height - tmp.y2;
0348         r->y2 = height - tmp.y1;
0349         break;
0350     case DRM_MODE_ROTATE_270:
0351         tmp = *r;
0352         r->x1 = tmp.y1;
0353         r->x2 = tmp.y2;
0354         r->y1 = height - tmp.x2;
0355         r->y2 = height - tmp.x1;
0356         break;
0357     default:
0358         break;
0359     }
0360 
0361     if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
0362         tmp = *r;
0363 
0364         if (rotation & DRM_MODE_REFLECT_X) {
0365             r->x1 = width - tmp.x2;
0366             r->x2 = width - tmp.x1;
0367         }
0368 
0369         if (rotation & DRM_MODE_REFLECT_Y) {
0370             r->y1 = height - tmp.y2;
0371             r->y2 = height - tmp.y1;
0372         }
0373     }
0374 }
0375 EXPORT_SYMBOL(drm_rect_rotate_inv);