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