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