1*17922c7fSriastradh /* $NetBSD: drm_rect.c,v 1.4 2021/12/19 01:15:00 riastradh Exp $ */
2efa246c0Sriastradh
39d20d926Sriastradh /*
49d20d926Sriastradh * Copyright (C) 2011-2013 Intel Corporation
59d20d926Sriastradh *
69d20d926Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
79d20d926Sriastradh * copy of this software and associated documentation files (the "Software"),
89d20d926Sriastradh * to deal in the Software without restriction, including without limitation
99d20d926Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
109d20d926Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
119d20d926Sriastradh * Software is furnished to do so, subject to the following conditions:
129d20d926Sriastradh *
139d20d926Sriastradh * The above copyright notice and this permission notice (including the next
149d20d926Sriastradh * paragraph) shall be included in all copies or substantial portions of the
159d20d926Sriastradh * Software.
169d20d926Sriastradh *
179d20d926Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
189d20d926Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
199d20d926Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
209d20d926Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
219d20d926Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
229d20d926Sriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
239d20d926Sriastradh * SOFTWARE.
249d20d926Sriastradh */
259d20d926Sriastradh
26efa246c0Sriastradh #include <sys/cdefs.h>
27*17922c7fSriastradh __KERNEL_RCSID(0, "$NetBSD: drm_rect.c,v 1.4 2021/12/19 01:15:00 riastradh Exp $");
28efa246c0Sriastradh
299d20d926Sriastradh #include <linux/errno.h>
309d20d926Sriastradh #include <linux/export.h>
319d20d926Sriastradh #include <linux/kernel.h>
32*17922c7fSriastradh #include <linux/math64.h>
3341ec0267Sriastradh
3441ec0267Sriastradh #include <drm/drm_mode.h>
3541ec0267Sriastradh #include <drm/drm_print.h>
369d20d926Sriastradh #include <drm/drm_rect.h>
379d20d926Sriastradh
389d20d926Sriastradh /**
399d20d926Sriastradh * drm_rect_intersect - intersect two rectangles
409d20d926Sriastradh * @r1: first rectangle
419d20d926Sriastradh * @r2: second rectangle
429d20d926Sriastradh *
439d20d926Sriastradh * Calculate the intersection of rectangles @r1 and @r2.
449d20d926Sriastradh * @r1 will be overwritten with the intersection.
459d20d926Sriastradh *
469d20d926Sriastradh * RETURNS:
479d20d926Sriastradh * %true if rectangle @r1 is still visible after the operation,
489d20d926Sriastradh * %false otherwise.
499d20d926Sriastradh */
drm_rect_intersect(struct drm_rect * r1,const struct drm_rect * r2)509d20d926Sriastradh bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
519d20d926Sriastradh {
529d20d926Sriastradh r1->x1 = max(r1->x1, r2->x1);
539d20d926Sriastradh r1->y1 = max(r1->y1, r2->y1);
549d20d926Sriastradh r1->x2 = min(r1->x2, r2->x2);
559d20d926Sriastradh r1->y2 = min(r1->y2, r2->y2);
569d20d926Sriastradh
579d20d926Sriastradh return drm_rect_visible(r1);
589d20d926Sriastradh }
599d20d926Sriastradh EXPORT_SYMBOL(drm_rect_intersect);
609d20d926Sriastradh
clip_scaled(int src,int dst,int * clip)6141ec0267Sriastradh static u32 clip_scaled(int src, int dst, int *clip)
6241ec0267Sriastradh {
6341ec0267Sriastradh u64 tmp;
6441ec0267Sriastradh
6541ec0267Sriastradh if (dst == 0)
6641ec0267Sriastradh return 0;
6741ec0267Sriastradh
6841ec0267Sriastradh /* Only clip what we have. Keeps the result bounded. */
6941ec0267Sriastradh *clip = min(*clip, dst);
7041ec0267Sriastradh
7141ec0267Sriastradh tmp = mul_u32_u32(src, dst - *clip);
7241ec0267Sriastradh
7341ec0267Sriastradh /*
7441ec0267Sriastradh * Round toward 1.0 when clipping so that we don't accidentally
7541ec0267Sriastradh * change upscaling to downscaling or vice versa.
7641ec0267Sriastradh */
7741ec0267Sriastradh if (src < (dst << 16))
7841ec0267Sriastradh return DIV_ROUND_UP_ULL(tmp, dst);
7941ec0267Sriastradh else
8041ec0267Sriastradh return DIV_ROUND_DOWN_ULL(tmp, dst);
8141ec0267Sriastradh }
8241ec0267Sriastradh
839d20d926Sriastradh /**
849d20d926Sriastradh * drm_rect_clip_scaled - perform a scaled clip operation
859d20d926Sriastradh * @src: source window rectangle
869d20d926Sriastradh * @dst: destination window rectangle
879d20d926Sriastradh * @clip: clip rectangle
889d20d926Sriastradh *
899d20d926Sriastradh * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
9041ec0267Sriastradh * the corresponding amounts, retaining the vertical and horizontal scaling
9141ec0267Sriastradh * factors from @src to @dst.
929d20d926Sriastradh *
939d20d926Sriastradh * RETURNS:
9441ec0267Sriastradh *
959d20d926Sriastradh * %true if rectangle @dst is still visible after being clipped,
9641ec0267Sriastradh * %false otherwise.
979d20d926Sriastradh */
drm_rect_clip_scaled(struct drm_rect * src,struct drm_rect * dst,const struct drm_rect * clip)989d20d926Sriastradh bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
9941ec0267Sriastradh const struct drm_rect *clip)
1009d20d926Sriastradh {
1019d20d926Sriastradh int diff;
1029d20d926Sriastradh
1039d20d926Sriastradh diff = clip->x1 - dst->x1;
1049d20d926Sriastradh if (diff > 0) {
10541ec0267Sriastradh u32 new_src_w = clip_scaled(drm_rect_width(src),
10641ec0267Sriastradh drm_rect_width(dst), &diff);
10741ec0267Sriastradh
10841ec0267Sriastradh src->x1 = src->x2 - new_src_w;
10941ec0267Sriastradh dst->x1 += diff;
1109d20d926Sriastradh }
1119d20d926Sriastradh diff = clip->y1 - dst->y1;
1129d20d926Sriastradh if (diff > 0) {
11341ec0267Sriastradh u32 new_src_h = clip_scaled(drm_rect_height(src),
11441ec0267Sriastradh drm_rect_height(dst), &diff);
11541ec0267Sriastradh
11641ec0267Sriastradh src->y1 = src->y2 - new_src_h;
11741ec0267Sriastradh dst->y1 += diff;
1189d20d926Sriastradh }
1199d20d926Sriastradh diff = dst->x2 - clip->x2;
1209d20d926Sriastradh if (diff > 0) {
12141ec0267Sriastradh u32 new_src_w = clip_scaled(drm_rect_width(src),
12241ec0267Sriastradh drm_rect_width(dst), &diff);
12341ec0267Sriastradh
12441ec0267Sriastradh src->x2 = src->x1 + new_src_w;
12541ec0267Sriastradh dst->x2 -= diff;
1269d20d926Sriastradh }
1279d20d926Sriastradh diff = dst->y2 - clip->y2;
1289d20d926Sriastradh if (diff > 0) {
12941ec0267Sriastradh u32 new_src_h = clip_scaled(drm_rect_height(src),
13041ec0267Sriastradh drm_rect_height(dst), &diff);
13141ec0267Sriastradh
13241ec0267Sriastradh src->y2 = src->y1 + new_src_h;
13341ec0267Sriastradh dst->y2 -= diff;
1349d20d926Sriastradh }
1359d20d926Sriastradh
13641ec0267Sriastradh return drm_rect_visible(dst);
1379d20d926Sriastradh }
1389d20d926Sriastradh EXPORT_SYMBOL(drm_rect_clip_scaled);
1399d20d926Sriastradh
drm_calc_scale(int src,int dst)1409d20d926Sriastradh static int drm_calc_scale(int src, int dst)
1419d20d926Sriastradh {
1429d20d926Sriastradh int scale = 0;
1439d20d926Sriastradh
14441ec0267Sriastradh if (WARN_ON(src < 0 || dst < 0))
1459d20d926Sriastradh return -EINVAL;
1469d20d926Sriastradh
1479d20d926Sriastradh if (dst == 0)
1489d20d926Sriastradh return 0;
1499d20d926Sriastradh
15041ec0267Sriastradh if (src > (dst << 16))
15141ec0267Sriastradh return DIV_ROUND_UP(src, dst);
15241ec0267Sriastradh else
1539d20d926Sriastradh scale = src / dst;
1549d20d926Sriastradh
1559d20d926Sriastradh return scale;
1569d20d926Sriastradh }
1579d20d926Sriastradh
1589d20d926Sriastradh /**
1599d20d926Sriastradh * drm_rect_calc_hscale - calculate the horizontal scaling factor
1609d20d926Sriastradh * @src: source window rectangle
1619d20d926Sriastradh * @dst: destination window rectangle
1629d20d926Sriastradh * @min_hscale: minimum allowed horizontal scaling factor
1639d20d926Sriastradh * @max_hscale: maximum allowed horizontal scaling factor
1649d20d926Sriastradh *
1659d20d926Sriastradh * Calculate the horizontal scaling factor as
1669d20d926Sriastradh * (@src width) / (@dst width).
1679d20d926Sriastradh *
16841ec0267Sriastradh * If the scale is below 1 << 16, round down. If the scale is above
16941ec0267Sriastradh * 1 << 16, round up. This will calculate the scale with the most
17041ec0267Sriastradh * pessimistic limit calculation.
17141ec0267Sriastradh *
1729d20d926Sriastradh * RETURNS:
1739d20d926Sriastradh * The horizontal scaling factor, or errno of out of limits.
1749d20d926Sriastradh */
drm_rect_calc_hscale(const struct drm_rect * src,const struct drm_rect * dst,int min_hscale,int max_hscale)1759d20d926Sriastradh int drm_rect_calc_hscale(const struct drm_rect *src,
1769d20d926Sriastradh const struct drm_rect *dst,
1779d20d926Sriastradh int min_hscale, int max_hscale)
1789d20d926Sriastradh {
1799d20d926Sriastradh int src_w = drm_rect_width(src);
1809d20d926Sriastradh int dst_w = drm_rect_width(dst);
1819d20d926Sriastradh int hscale = drm_calc_scale(src_w, dst_w);
1829d20d926Sriastradh
1839d20d926Sriastradh if (hscale < 0 || dst_w == 0)
1849d20d926Sriastradh return hscale;
1859d20d926Sriastradh
1869d20d926Sriastradh if (hscale < min_hscale || hscale > max_hscale)
1879d20d926Sriastradh return -ERANGE;
1889d20d926Sriastradh
1899d20d926Sriastradh return hscale;
1909d20d926Sriastradh }
1919d20d926Sriastradh EXPORT_SYMBOL(drm_rect_calc_hscale);
1929d20d926Sriastradh
1939d20d926Sriastradh /**
1949d20d926Sriastradh * drm_rect_calc_vscale - calculate the vertical scaling factor
1959d20d926Sriastradh * @src: source window rectangle
1969d20d926Sriastradh * @dst: destination window rectangle
1979d20d926Sriastradh * @min_vscale: minimum allowed vertical scaling factor
1989d20d926Sriastradh * @max_vscale: maximum allowed vertical scaling factor
1999d20d926Sriastradh *
2009d20d926Sriastradh * Calculate the vertical scaling factor as
2019d20d926Sriastradh * (@src height) / (@dst height).
2029d20d926Sriastradh *
20341ec0267Sriastradh * If the scale is below 1 << 16, round down. If the scale is above
20441ec0267Sriastradh * 1 << 16, round up. This will calculate the scale with the most
20541ec0267Sriastradh * pessimistic limit calculation.
20641ec0267Sriastradh *
2079d20d926Sriastradh * RETURNS:
2089d20d926Sriastradh * The vertical scaling factor, or errno of out of limits.
2099d20d926Sriastradh */
drm_rect_calc_vscale(const struct drm_rect * src,const struct drm_rect * dst,int min_vscale,int max_vscale)2109d20d926Sriastradh int drm_rect_calc_vscale(const struct drm_rect *src,
2119d20d926Sriastradh const struct drm_rect *dst,
2129d20d926Sriastradh int min_vscale, int max_vscale)
2139d20d926Sriastradh {
2149d20d926Sriastradh int src_h = drm_rect_height(src);
2159d20d926Sriastradh int dst_h = drm_rect_height(dst);
2169d20d926Sriastradh int vscale = drm_calc_scale(src_h, dst_h);
2179d20d926Sriastradh
2189d20d926Sriastradh if (vscale < 0 || dst_h == 0)
2199d20d926Sriastradh return vscale;
2209d20d926Sriastradh
2219d20d926Sriastradh if (vscale < min_vscale || vscale > max_vscale)
2229d20d926Sriastradh return -ERANGE;
2239d20d926Sriastradh
2249d20d926Sriastradh return vscale;
2259d20d926Sriastradh }
2269d20d926Sriastradh EXPORT_SYMBOL(drm_rect_calc_vscale);
2279d20d926Sriastradh
2289d20d926Sriastradh /**
2299d20d926Sriastradh * drm_rect_debug_print - print the rectangle information
23041ec0267Sriastradh * @prefix: prefix string
2319d20d926Sriastradh * @r: rectangle to print
2329d20d926Sriastradh * @fixed_point: rectangle is in 16.16 fixed point format
2339d20d926Sriastradh */
drm_rect_debug_print(const char * prefix,const struct drm_rect * r,bool fixed_point)23441ec0267Sriastradh void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
2359d20d926Sriastradh {
2369d20d926Sriastradh if (fixed_point)
23741ec0267Sriastradh DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r));
2389d20d926Sriastradh else
23941ec0267Sriastradh DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r));
2409d20d926Sriastradh }
2419d20d926Sriastradh EXPORT_SYMBOL(drm_rect_debug_print);
242efa246c0Sriastradh
243efa246c0Sriastradh /**
244efa246c0Sriastradh * drm_rect_rotate - Rotate the rectangle
245efa246c0Sriastradh * @r: rectangle to be rotated
246efa246c0Sriastradh * @width: Width of the coordinate space
247efa246c0Sriastradh * @height: Height of the coordinate space
248efa246c0Sriastradh * @rotation: Transformation to be applied
249efa246c0Sriastradh *
250efa246c0Sriastradh * Apply @rotation to the coordinates of rectangle @r.
251efa246c0Sriastradh *
252efa246c0Sriastradh * @width and @height combined with @rotation define
253efa246c0Sriastradh * the location of the new origin.
254efa246c0Sriastradh *
255efa246c0Sriastradh * @width correcsponds to the horizontal and @height
256efa246c0Sriastradh * to the vertical axis of the untransformed coordinate
257efa246c0Sriastradh * space.
258efa246c0Sriastradh */
drm_rect_rotate(struct drm_rect * r,int width,int height,unsigned int rotation)259efa246c0Sriastradh void drm_rect_rotate(struct drm_rect *r,
260efa246c0Sriastradh int width, int height,
261efa246c0Sriastradh unsigned int rotation)
262efa246c0Sriastradh {
263efa246c0Sriastradh struct drm_rect tmp;
264efa246c0Sriastradh
26541ec0267Sriastradh if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
266efa246c0Sriastradh tmp = *r;
267efa246c0Sriastradh
26841ec0267Sriastradh if (rotation & DRM_MODE_REFLECT_X) {
269efa246c0Sriastradh r->x1 = width - tmp.x2;
270efa246c0Sriastradh r->x2 = width - tmp.x1;
271efa246c0Sriastradh }
272efa246c0Sriastradh
27341ec0267Sriastradh if (rotation & DRM_MODE_REFLECT_Y) {
274efa246c0Sriastradh r->y1 = height - tmp.y2;
275efa246c0Sriastradh r->y2 = height - tmp.y1;
276efa246c0Sriastradh }
277efa246c0Sriastradh }
278efa246c0Sriastradh
27941ec0267Sriastradh switch (rotation & DRM_MODE_ROTATE_MASK) {
28041ec0267Sriastradh case DRM_MODE_ROTATE_0:
281efa246c0Sriastradh break;
28241ec0267Sriastradh case DRM_MODE_ROTATE_90:
283efa246c0Sriastradh tmp = *r;
284efa246c0Sriastradh r->x1 = tmp.y1;
285efa246c0Sriastradh r->x2 = tmp.y2;
286efa246c0Sriastradh r->y1 = width - tmp.x2;
287efa246c0Sriastradh r->y2 = width - tmp.x1;
288efa246c0Sriastradh break;
28941ec0267Sriastradh case DRM_MODE_ROTATE_180:
290efa246c0Sriastradh tmp = *r;
291efa246c0Sriastradh r->x1 = width - tmp.x2;
292efa246c0Sriastradh r->x2 = width - tmp.x1;
293efa246c0Sriastradh r->y1 = height - tmp.y2;
294efa246c0Sriastradh r->y2 = height - tmp.y1;
295efa246c0Sriastradh break;
29641ec0267Sriastradh case DRM_MODE_ROTATE_270:
297efa246c0Sriastradh tmp = *r;
298efa246c0Sriastradh r->x1 = height - tmp.y2;
299efa246c0Sriastradh r->x2 = height - tmp.y1;
300efa246c0Sriastradh r->y1 = tmp.x1;
301efa246c0Sriastradh r->y2 = tmp.x2;
302efa246c0Sriastradh break;
303efa246c0Sriastradh default:
304efa246c0Sriastradh break;
305efa246c0Sriastradh }
306efa246c0Sriastradh }
307efa246c0Sriastradh EXPORT_SYMBOL(drm_rect_rotate);
308efa246c0Sriastradh
309efa246c0Sriastradh /**
310efa246c0Sriastradh * drm_rect_rotate_inv - Inverse rotate the rectangle
311efa246c0Sriastradh * @r: rectangle to be rotated
312efa246c0Sriastradh * @width: Width of the coordinate space
313efa246c0Sriastradh * @height: Height of the coordinate space
314efa246c0Sriastradh * @rotation: Transformation whose inverse is to be applied
315efa246c0Sriastradh *
316efa246c0Sriastradh * Apply the inverse of @rotation to the coordinates
317efa246c0Sriastradh * of rectangle @r.
318efa246c0Sriastradh *
319efa246c0Sriastradh * @width and @height combined with @rotation define
320efa246c0Sriastradh * the location of the new origin.
321efa246c0Sriastradh *
322efa246c0Sriastradh * @width correcsponds to the horizontal and @height
323efa246c0Sriastradh * to the vertical axis of the original untransformed
324efa246c0Sriastradh * coordinate space, so that you never have to flip
325efa246c0Sriastradh * them when doing a rotatation and its inverse.
32641ec0267Sriastradh * That is, if you do ::
327efa246c0Sriastradh *
32841ec0267Sriastradh * drm_rect_rotate(&r, width, height, rotation);
32941ec0267Sriastradh * drm_rect_rotate_inv(&r, width, height, rotation);
330efa246c0Sriastradh *
331efa246c0Sriastradh * you will always get back the original rectangle.
332efa246c0Sriastradh */
drm_rect_rotate_inv(struct drm_rect * r,int width,int height,unsigned int rotation)333efa246c0Sriastradh void drm_rect_rotate_inv(struct drm_rect *r,
334efa246c0Sriastradh int width, int height,
335efa246c0Sriastradh unsigned int rotation)
336efa246c0Sriastradh {
337efa246c0Sriastradh struct drm_rect tmp;
338efa246c0Sriastradh
33941ec0267Sriastradh switch (rotation & DRM_MODE_ROTATE_MASK) {
34041ec0267Sriastradh case DRM_MODE_ROTATE_0:
341efa246c0Sriastradh break;
34241ec0267Sriastradh case DRM_MODE_ROTATE_90:
343efa246c0Sriastradh tmp = *r;
344efa246c0Sriastradh r->x1 = width - tmp.y2;
345efa246c0Sriastradh r->x2 = width - tmp.y1;
346efa246c0Sriastradh r->y1 = tmp.x1;
347efa246c0Sriastradh r->y2 = tmp.x2;
348efa246c0Sriastradh break;
34941ec0267Sriastradh case DRM_MODE_ROTATE_180:
350efa246c0Sriastradh tmp = *r;
351efa246c0Sriastradh r->x1 = width - tmp.x2;
352efa246c0Sriastradh r->x2 = width - tmp.x1;
353efa246c0Sriastradh r->y1 = height - tmp.y2;
354efa246c0Sriastradh r->y2 = height - tmp.y1;
355efa246c0Sriastradh break;
35641ec0267Sriastradh case DRM_MODE_ROTATE_270:
357efa246c0Sriastradh tmp = *r;
358efa246c0Sriastradh r->x1 = tmp.y1;
359efa246c0Sriastradh r->x2 = tmp.y2;
360efa246c0Sriastradh r->y1 = height - tmp.x2;
361efa246c0Sriastradh r->y2 = height - tmp.x1;
362efa246c0Sriastradh break;
363efa246c0Sriastradh default:
364efa246c0Sriastradh break;
365efa246c0Sriastradh }
366efa246c0Sriastradh
36741ec0267Sriastradh if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
368efa246c0Sriastradh tmp = *r;
369efa246c0Sriastradh
37041ec0267Sriastradh if (rotation & DRM_MODE_REFLECT_X) {
371efa246c0Sriastradh r->x1 = width - tmp.x2;
372efa246c0Sriastradh r->x2 = width - tmp.x1;
373efa246c0Sriastradh }
374efa246c0Sriastradh
37541ec0267Sriastradh if (rotation & DRM_MODE_REFLECT_Y) {
376efa246c0Sriastradh r->y1 = height - tmp.y2;
377efa246c0Sriastradh r->y2 = height - tmp.y1;
378efa246c0Sriastradh }
379efa246c0Sriastradh }
380efa246c0Sriastradh }
381efa246c0Sriastradh EXPORT_SYMBOL(drm_rect_rotate_inv);
382