drm_rect.c revision 1.3 1 1.2 riastrad /* $NetBSD: drm_rect.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $ */
2 1.2 riastrad
3 1.1 riastrad /*
4 1.1 riastrad * Copyright (C) 2011-2013 Intel Corporation
5 1.1 riastrad *
6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a
7 1.1 riastrad * copy of this software and associated documentation files (the "Software"),
8 1.1 riastrad * to deal in the Software without restriction, including without limitation
9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the
11 1.1 riastrad * Software is furnished to do so, subject to the following conditions:
12 1.1 riastrad *
13 1.1 riastrad * The above copyright notice and this permission notice (including the next
14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the
15 1.1 riastrad * Software.
16 1.1 riastrad *
17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 1.1 riastrad * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 1.1 riastrad * SOFTWARE.
24 1.1 riastrad */
25 1.1 riastrad
26 1.2 riastrad #include <sys/cdefs.h>
27 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_rect.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $");
28 1.2 riastrad
29 1.1 riastrad #include <linux/errno.h>
30 1.1 riastrad #include <linux/export.h>
31 1.1 riastrad #include <linux/kernel.h>
32 1.3 riastrad
33 1.3 riastrad #include <drm/drm_mode.h>
34 1.3 riastrad #include <drm/drm_print.h>
35 1.1 riastrad #include <drm/drm_rect.h>
36 1.1 riastrad
37 1.1 riastrad /**
38 1.1 riastrad * drm_rect_intersect - intersect two rectangles
39 1.1 riastrad * @r1: first rectangle
40 1.1 riastrad * @r2: second rectangle
41 1.1 riastrad *
42 1.1 riastrad * Calculate the intersection of rectangles @r1 and @r2.
43 1.1 riastrad * @r1 will be overwritten with the intersection.
44 1.1 riastrad *
45 1.1 riastrad * RETURNS:
46 1.1 riastrad * %true if rectangle @r1 is still visible after the operation,
47 1.1 riastrad * %false otherwise.
48 1.1 riastrad */
49 1.1 riastrad bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
50 1.1 riastrad {
51 1.1 riastrad r1->x1 = max(r1->x1, r2->x1);
52 1.1 riastrad r1->y1 = max(r1->y1, r2->y1);
53 1.1 riastrad r1->x2 = min(r1->x2, r2->x2);
54 1.1 riastrad r1->y2 = min(r1->y2, r2->y2);
55 1.1 riastrad
56 1.1 riastrad return drm_rect_visible(r1);
57 1.1 riastrad }
58 1.1 riastrad EXPORT_SYMBOL(drm_rect_intersect);
59 1.1 riastrad
60 1.3 riastrad static u32 clip_scaled(int src, int dst, int *clip)
61 1.3 riastrad {
62 1.3 riastrad u64 tmp;
63 1.3 riastrad
64 1.3 riastrad if (dst == 0)
65 1.3 riastrad return 0;
66 1.3 riastrad
67 1.3 riastrad /* Only clip what we have. Keeps the result bounded. */
68 1.3 riastrad *clip = min(*clip, dst);
69 1.3 riastrad
70 1.3 riastrad tmp = mul_u32_u32(src, dst - *clip);
71 1.3 riastrad
72 1.3 riastrad /*
73 1.3 riastrad * Round toward 1.0 when clipping so that we don't accidentally
74 1.3 riastrad * change upscaling to downscaling or vice versa.
75 1.3 riastrad */
76 1.3 riastrad if (src < (dst << 16))
77 1.3 riastrad return DIV_ROUND_UP_ULL(tmp, dst);
78 1.3 riastrad else
79 1.3 riastrad return DIV_ROUND_DOWN_ULL(tmp, dst);
80 1.3 riastrad }
81 1.3 riastrad
82 1.1 riastrad /**
83 1.1 riastrad * drm_rect_clip_scaled - perform a scaled clip operation
84 1.1 riastrad * @src: source window rectangle
85 1.1 riastrad * @dst: destination window rectangle
86 1.1 riastrad * @clip: clip rectangle
87 1.1 riastrad *
88 1.1 riastrad * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
89 1.3 riastrad * the corresponding amounts, retaining the vertical and horizontal scaling
90 1.3 riastrad * factors from @src to @dst.
91 1.1 riastrad *
92 1.1 riastrad * RETURNS:
93 1.3 riastrad *
94 1.1 riastrad * %true if rectangle @dst is still visible after being clipped,
95 1.3 riastrad * %false otherwise.
96 1.1 riastrad */
97 1.1 riastrad bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
98 1.3 riastrad const struct drm_rect *clip)
99 1.1 riastrad {
100 1.1 riastrad int diff;
101 1.1 riastrad
102 1.1 riastrad diff = clip->x1 - dst->x1;
103 1.1 riastrad if (diff > 0) {
104 1.3 riastrad u32 new_src_w = clip_scaled(drm_rect_width(src),
105 1.3 riastrad drm_rect_width(dst), &diff);
106 1.3 riastrad
107 1.3 riastrad src->x1 = src->x2 - new_src_w;
108 1.3 riastrad dst->x1 += diff;
109 1.1 riastrad }
110 1.1 riastrad diff = clip->y1 - dst->y1;
111 1.1 riastrad if (diff > 0) {
112 1.3 riastrad u32 new_src_h = clip_scaled(drm_rect_height(src),
113 1.3 riastrad drm_rect_height(dst), &diff);
114 1.3 riastrad
115 1.3 riastrad src->y1 = src->y2 - new_src_h;
116 1.3 riastrad dst->y1 += diff;
117 1.1 riastrad }
118 1.1 riastrad diff = dst->x2 - clip->x2;
119 1.1 riastrad if (diff > 0) {
120 1.3 riastrad u32 new_src_w = clip_scaled(drm_rect_width(src),
121 1.3 riastrad drm_rect_width(dst), &diff);
122 1.3 riastrad
123 1.3 riastrad src->x2 = src->x1 + new_src_w;
124 1.3 riastrad dst->x2 -= diff;
125 1.1 riastrad }
126 1.1 riastrad diff = dst->y2 - clip->y2;
127 1.1 riastrad if (diff > 0) {
128 1.3 riastrad u32 new_src_h = clip_scaled(drm_rect_height(src),
129 1.3 riastrad drm_rect_height(dst), &diff);
130 1.3 riastrad
131 1.3 riastrad src->y2 = src->y1 + new_src_h;
132 1.3 riastrad dst->y2 -= diff;
133 1.1 riastrad }
134 1.1 riastrad
135 1.3 riastrad return drm_rect_visible(dst);
136 1.1 riastrad }
137 1.1 riastrad EXPORT_SYMBOL(drm_rect_clip_scaled);
138 1.1 riastrad
139 1.1 riastrad static int drm_calc_scale(int src, int dst)
140 1.1 riastrad {
141 1.1 riastrad int scale = 0;
142 1.1 riastrad
143 1.3 riastrad if (WARN_ON(src < 0 || dst < 0))
144 1.1 riastrad return -EINVAL;
145 1.1 riastrad
146 1.1 riastrad if (dst == 0)
147 1.1 riastrad return 0;
148 1.1 riastrad
149 1.3 riastrad if (src > (dst << 16))
150 1.3 riastrad return DIV_ROUND_UP(src, dst);
151 1.3 riastrad else
152 1.3 riastrad scale = src / dst;
153 1.1 riastrad
154 1.1 riastrad return scale;
155 1.1 riastrad }
156 1.1 riastrad
157 1.1 riastrad /**
158 1.1 riastrad * drm_rect_calc_hscale - calculate the horizontal scaling factor
159 1.1 riastrad * @src: source window rectangle
160 1.1 riastrad * @dst: destination window rectangle
161 1.1 riastrad * @min_hscale: minimum allowed horizontal scaling factor
162 1.1 riastrad * @max_hscale: maximum allowed horizontal scaling factor
163 1.1 riastrad *
164 1.1 riastrad * Calculate the horizontal scaling factor as
165 1.1 riastrad * (@src width) / (@dst width).
166 1.1 riastrad *
167 1.3 riastrad * If the scale is below 1 << 16, round down. If the scale is above
168 1.3 riastrad * 1 << 16, round up. This will calculate the scale with the most
169 1.3 riastrad * pessimistic limit calculation.
170 1.3 riastrad *
171 1.1 riastrad * RETURNS:
172 1.1 riastrad * The horizontal scaling factor, or errno of out of limits.
173 1.1 riastrad */
174 1.1 riastrad int drm_rect_calc_hscale(const struct drm_rect *src,
175 1.1 riastrad const struct drm_rect *dst,
176 1.1 riastrad int min_hscale, int max_hscale)
177 1.1 riastrad {
178 1.1 riastrad int src_w = drm_rect_width(src);
179 1.1 riastrad int dst_w = drm_rect_width(dst);
180 1.1 riastrad int hscale = drm_calc_scale(src_w, dst_w);
181 1.1 riastrad
182 1.1 riastrad if (hscale < 0 || dst_w == 0)
183 1.1 riastrad return hscale;
184 1.1 riastrad
185 1.1 riastrad if (hscale < min_hscale || hscale > max_hscale)
186 1.1 riastrad return -ERANGE;
187 1.1 riastrad
188 1.1 riastrad return hscale;
189 1.1 riastrad }
190 1.1 riastrad EXPORT_SYMBOL(drm_rect_calc_hscale);
191 1.1 riastrad
192 1.1 riastrad /**
193 1.1 riastrad * drm_rect_calc_vscale - calculate the vertical scaling factor
194 1.1 riastrad * @src: source window rectangle
195 1.1 riastrad * @dst: destination window rectangle
196 1.1 riastrad * @min_vscale: minimum allowed vertical scaling factor
197 1.1 riastrad * @max_vscale: maximum allowed vertical scaling factor
198 1.1 riastrad *
199 1.1 riastrad * Calculate the vertical scaling factor as
200 1.1 riastrad * (@src height) / (@dst height).
201 1.1 riastrad *
202 1.3 riastrad * If the scale is below 1 << 16, round down. If the scale is above
203 1.3 riastrad * 1 << 16, round up. This will calculate the scale with the most
204 1.3 riastrad * pessimistic limit calculation.
205 1.3 riastrad *
206 1.1 riastrad * RETURNS:
207 1.1 riastrad * The vertical scaling factor, or errno of out of limits.
208 1.1 riastrad */
209 1.1 riastrad int drm_rect_calc_vscale(const struct drm_rect *src,
210 1.1 riastrad const struct drm_rect *dst,
211 1.1 riastrad int min_vscale, int max_vscale)
212 1.1 riastrad {
213 1.1 riastrad int src_h = drm_rect_height(src);
214 1.1 riastrad int dst_h = drm_rect_height(dst);
215 1.1 riastrad int vscale = drm_calc_scale(src_h, dst_h);
216 1.1 riastrad
217 1.1 riastrad if (vscale < 0 || dst_h == 0)
218 1.1 riastrad return vscale;
219 1.1 riastrad
220 1.1 riastrad if (vscale < min_vscale || vscale > max_vscale)
221 1.1 riastrad return -ERANGE;
222 1.1 riastrad
223 1.1 riastrad return vscale;
224 1.1 riastrad }
225 1.1 riastrad EXPORT_SYMBOL(drm_rect_calc_vscale);
226 1.1 riastrad
227 1.1 riastrad /**
228 1.1 riastrad * drm_rect_debug_print - print the rectangle information
229 1.3 riastrad * @prefix: prefix string
230 1.1 riastrad * @r: rectangle to print
231 1.1 riastrad * @fixed_point: rectangle is in 16.16 fixed point format
232 1.1 riastrad */
233 1.3 riastrad void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
234 1.1 riastrad {
235 1.1 riastrad if (fixed_point)
236 1.3 riastrad DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r));
237 1.1 riastrad else
238 1.3 riastrad DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r));
239 1.1 riastrad }
240 1.1 riastrad EXPORT_SYMBOL(drm_rect_debug_print);
241 1.2 riastrad
242 1.2 riastrad /**
243 1.2 riastrad * drm_rect_rotate - Rotate the rectangle
244 1.2 riastrad * @r: rectangle to be rotated
245 1.2 riastrad * @width: Width of the coordinate space
246 1.2 riastrad * @height: Height of the coordinate space
247 1.2 riastrad * @rotation: Transformation to be applied
248 1.2 riastrad *
249 1.2 riastrad * Apply @rotation to the coordinates of rectangle @r.
250 1.2 riastrad *
251 1.2 riastrad * @width and @height combined with @rotation define
252 1.2 riastrad * the location of the new origin.
253 1.2 riastrad *
254 1.2 riastrad * @width correcsponds to the horizontal and @height
255 1.2 riastrad * to the vertical axis of the untransformed coordinate
256 1.2 riastrad * space.
257 1.2 riastrad */
258 1.2 riastrad void drm_rect_rotate(struct drm_rect *r,
259 1.2 riastrad int width, int height,
260 1.2 riastrad unsigned int rotation)
261 1.2 riastrad {
262 1.2 riastrad struct drm_rect tmp;
263 1.2 riastrad
264 1.3 riastrad if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
265 1.2 riastrad tmp = *r;
266 1.2 riastrad
267 1.3 riastrad if (rotation & DRM_MODE_REFLECT_X) {
268 1.2 riastrad r->x1 = width - tmp.x2;
269 1.2 riastrad r->x2 = width - tmp.x1;
270 1.2 riastrad }
271 1.2 riastrad
272 1.3 riastrad if (rotation & DRM_MODE_REFLECT_Y) {
273 1.2 riastrad r->y1 = height - tmp.y2;
274 1.2 riastrad r->y2 = height - tmp.y1;
275 1.2 riastrad }
276 1.2 riastrad }
277 1.2 riastrad
278 1.3 riastrad switch (rotation & DRM_MODE_ROTATE_MASK) {
279 1.3 riastrad case DRM_MODE_ROTATE_0:
280 1.2 riastrad break;
281 1.3 riastrad case DRM_MODE_ROTATE_90:
282 1.2 riastrad tmp = *r;
283 1.2 riastrad r->x1 = tmp.y1;
284 1.2 riastrad r->x2 = tmp.y2;
285 1.2 riastrad r->y1 = width - tmp.x2;
286 1.2 riastrad r->y2 = width - tmp.x1;
287 1.2 riastrad break;
288 1.3 riastrad case DRM_MODE_ROTATE_180:
289 1.2 riastrad tmp = *r;
290 1.2 riastrad r->x1 = width - tmp.x2;
291 1.2 riastrad r->x2 = width - tmp.x1;
292 1.2 riastrad r->y1 = height - tmp.y2;
293 1.2 riastrad r->y2 = height - tmp.y1;
294 1.2 riastrad break;
295 1.3 riastrad case DRM_MODE_ROTATE_270:
296 1.2 riastrad tmp = *r;
297 1.2 riastrad r->x1 = height - tmp.y2;
298 1.2 riastrad r->x2 = height - tmp.y1;
299 1.2 riastrad r->y1 = tmp.x1;
300 1.2 riastrad r->y2 = tmp.x2;
301 1.2 riastrad break;
302 1.2 riastrad default:
303 1.2 riastrad break;
304 1.2 riastrad }
305 1.2 riastrad }
306 1.2 riastrad EXPORT_SYMBOL(drm_rect_rotate);
307 1.2 riastrad
308 1.2 riastrad /**
309 1.2 riastrad * drm_rect_rotate_inv - Inverse rotate the rectangle
310 1.2 riastrad * @r: rectangle to be rotated
311 1.2 riastrad * @width: Width of the coordinate space
312 1.2 riastrad * @height: Height of the coordinate space
313 1.2 riastrad * @rotation: Transformation whose inverse is to be applied
314 1.2 riastrad *
315 1.2 riastrad * Apply the inverse of @rotation to the coordinates
316 1.2 riastrad * of rectangle @r.
317 1.2 riastrad *
318 1.2 riastrad * @width and @height combined with @rotation define
319 1.2 riastrad * the location of the new origin.
320 1.2 riastrad *
321 1.2 riastrad * @width correcsponds to the horizontal and @height
322 1.2 riastrad * to the vertical axis of the original untransformed
323 1.2 riastrad * coordinate space, so that you never have to flip
324 1.2 riastrad * them when doing a rotatation and its inverse.
325 1.3 riastrad * That is, if you do ::
326 1.2 riastrad *
327 1.3 riastrad * drm_rect_rotate(&r, width, height, rotation);
328 1.3 riastrad * drm_rect_rotate_inv(&r, width, height, rotation);
329 1.2 riastrad *
330 1.2 riastrad * you will always get back the original rectangle.
331 1.2 riastrad */
332 1.2 riastrad void drm_rect_rotate_inv(struct drm_rect *r,
333 1.2 riastrad int width, int height,
334 1.2 riastrad unsigned int rotation)
335 1.2 riastrad {
336 1.2 riastrad struct drm_rect tmp;
337 1.2 riastrad
338 1.3 riastrad switch (rotation & DRM_MODE_ROTATE_MASK) {
339 1.3 riastrad case DRM_MODE_ROTATE_0:
340 1.2 riastrad break;
341 1.3 riastrad case DRM_MODE_ROTATE_90:
342 1.2 riastrad tmp = *r;
343 1.2 riastrad r->x1 = width - tmp.y2;
344 1.2 riastrad r->x2 = width - tmp.y1;
345 1.2 riastrad r->y1 = tmp.x1;
346 1.2 riastrad r->y2 = tmp.x2;
347 1.2 riastrad break;
348 1.3 riastrad case DRM_MODE_ROTATE_180:
349 1.2 riastrad tmp = *r;
350 1.2 riastrad r->x1 = width - tmp.x2;
351 1.2 riastrad r->x2 = width - tmp.x1;
352 1.2 riastrad r->y1 = height - tmp.y2;
353 1.2 riastrad r->y2 = height - tmp.y1;
354 1.2 riastrad break;
355 1.3 riastrad case DRM_MODE_ROTATE_270:
356 1.2 riastrad tmp = *r;
357 1.2 riastrad r->x1 = tmp.y1;
358 1.2 riastrad r->x2 = tmp.y2;
359 1.2 riastrad r->y1 = height - tmp.x2;
360 1.2 riastrad r->y2 = height - tmp.x1;
361 1.2 riastrad break;
362 1.2 riastrad default:
363 1.2 riastrad break;
364 1.2 riastrad }
365 1.2 riastrad
366 1.3 riastrad if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
367 1.2 riastrad tmp = *r;
368 1.2 riastrad
369 1.3 riastrad if (rotation & DRM_MODE_REFLECT_X) {
370 1.2 riastrad r->x1 = width - tmp.x2;
371 1.2 riastrad r->x2 = width - tmp.x1;
372 1.2 riastrad }
373 1.2 riastrad
374 1.3 riastrad if (rotation & DRM_MODE_REFLECT_Y) {
375 1.2 riastrad r->y1 = height - tmp.y2;
376 1.2 riastrad r->y2 = height - tmp.y1;
377 1.2 riastrad }
378 1.2 riastrad }
379 1.2 riastrad }
380 1.2 riastrad EXPORT_SYMBOL(drm_rect_rotate_inv);
381