Branch data 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 : 0 : bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
45 : : {
46 : 0 : r1->x1 = max(r1->x1, r2->x1);
47 : 0 : r1->y1 = max(r1->y1, r2->y1);
48 : 0 : r1->x2 = min(r1->x2, r2->x2);
49 : 0 : r1->y2 = min(r1->y2, r2->y2);
50 : :
51 [ # # ]: 0 : return drm_rect_visible(r1);
52 : : }
53 : : EXPORT_SYMBOL(drm_rect_intersect);
54 : :
55 : 0 : static u32 clip_scaled(int src, int dst, int *clip)
56 : : {
57 : 0 : u64 tmp;
58 : :
59 [ # # # # : 0 : if (dst == 0)
# # # # ]
60 : : return 0;
61 : :
62 : : /* Only clip what we have. Keeps the result bounded. */
63 : 0 : *clip = min(*clip, dst);
64 : :
65 [ # # # # : 0 : 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 [ # # # # : 0 : if (src < (dst << 16))
# # # # ]
72 : 0 : return DIV_ROUND_UP_ULL(tmp, dst);
73 : : else
74 : 0 : 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 the
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 : 0 : bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
93 : : const struct drm_rect *clip)
94 : : {
95 : 0 : int diff;
96 : :
97 : 0 : diff = clip->x1 - dst->x1;
98 [ # # ]: 0 : if (diff > 0) {
99 [ # # ]: 0 : u32 new_src_w = clip_scaled(drm_rect_width(src),
100 : : drm_rect_width(dst), &diff);
101 : :
102 : 0 : src->x1 = src->x2 - new_src_w;
103 : 0 : dst->x1 += diff;
104 : : }
105 : 0 : diff = clip->y1 - dst->y1;
106 [ # # ]: 0 : if (diff > 0) {
107 [ # # ]: 0 : u32 new_src_h = clip_scaled(drm_rect_height(src),
108 : : drm_rect_height(dst), &diff);
109 : :
110 : 0 : src->y1 = src->y2 - new_src_h;
111 : 0 : dst->y1 += diff;
112 : : }
113 : 0 : diff = dst->x2 - clip->x2;
114 [ # # ]: 0 : if (diff > 0) {
115 [ # # ]: 0 : u32 new_src_w = clip_scaled(drm_rect_width(src),
116 : : drm_rect_width(dst), &diff);
117 : :
118 : 0 : src->x2 = src->x1 + new_src_w;
119 : 0 : dst->x2 -= diff;
120 : : }
121 : 0 : diff = dst->y2 - clip->y2;
122 [ # # ]: 0 : if (diff > 0) {
123 [ # # ]: 0 : u32 new_src_h = clip_scaled(drm_rect_height(src),
124 : : drm_rect_height(dst), &diff);
125 : :
126 : 0 : src->y2 = src->y1 + new_src_h;
127 : 0 : dst->y2 -= diff;
128 : : }
129 : :
130 [ # # ]: 0 : return drm_rect_visible(dst);
131 : : }
132 : : EXPORT_SYMBOL(drm_rect_clip_scaled);
133 : :
134 : 0 : static int drm_calc_scale(int src, int dst)
135 : : {
136 : 0 : int scale = 0;
137 : :
138 [ # # # # ]: 0 : if (WARN_ON(src < 0 || dst < 0))
139 : : return -EINVAL;
140 : :
141 [ # # ]: 0 : if (dst == 0)
142 : : return 0;
143 : :
144 [ # # ]: 0 : if (src > (dst << 16))
145 : 0 : return DIV_ROUND_UP(src, dst);
146 : : else
147 : 0 : scale = src / dst;
148 : :
149 : 0 : 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 : 0 : 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 : 0 : int src_w = drm_rect_width(src);
174 : 0 : int dst_w = drm_rect_width(dst);
175 : 0 : int hscale = drm_calc_scale(src_w, dst_w);
176 : :
177 [ # # ]: 0 : if (hscale < 0 || dst_w == 0)
178 : : return hscale;
179 : :
180 [ # # ]: 0 : if (hscale < min_hscale || hscale > max_hscale)
181 : 0 : return -ERANGE;
182 : :
183 : : 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 : 0 : 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 : 0 : int src_h = drm_rect_height(src);
209 : 0 : int dst_h = drm_rect_height(dst);
210 : 0 : int vscale = drm_calc_scale(src_h, dst_h);
211 : :
212 [ # # ]: 0 : if (vscale < 0 || dst_h == 0)
213 : : return vscale;
214 : :
215 [ # # ]: 0 : if (vscale < min_vscale || vscale > max_vscale)
216 : 0 : return -ERANGE;
217 : :
218 : : 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 : 0 : void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
229 : : {
230 [ # # ]: 0 : if (fixed_point)
231 : 0 : DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r));
232 : : else
233 : 0 : DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r));
234 : 0 : }
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 : 0 : void drm_rect_rotate(struct drm_rect *r,
254 : : int width, int height,
255 : : unsigned int rotation)
256 : : {
257 : 0 : struct drm_rect tmp;
258 : :
259 [ # # ]: 0 : if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
260 : 0 : tmp = *r;
261 : :
262 [ # # ]: 0 : if (rotation & DRM_MODE_REFLECT_X) {
263 : 0 : r->x1 = width - tmp.x2;
264 : 0 : r->x2 = width - tmp.x1;
265 : : }
266 : :
267 [ # # ]: 0 : if (rotation & DRM_MODE_REFLECT_Y) {
268 : 0 : r->y1 = height - tmp.y2;
269 : 0 : r->y2 = height - tmp.y1;
270 : : }
271 : : }
272 : :
273 [ # # # # ]: 0 : switch (rotation & DRM_MODE_ROTATE_MASK) {
274 : : case DRM_MODE_ROTATE_0:
275 : : break;
276 : 0 : case DRM_MODE_ROTATE_90:
277 : 0 : tmp = *r;
278 : 0 : r->x1 = tmp.y1;
279 : 0 : r->x2 = tmp.y2;
280 : 0 : r->y1 = width - tmp.x2;
281 : 0 : r->y2 = width - tmp.x1;
282 : 0 : break;
283 : 0 : case DRM_MODE_ROTATE_180:
284 : 0 : tmp = *r;
285 : 0 : r->x1 = width - tmp.x2;
286 : 0 : r->x2 = width - tmp.x1;
287 : 0 : r->y1 = height - tmp.y2;
288 : 0 : r->y2 = height - tmp.y1;
289 : 0 : break;
290 : 0 : case DRM_MODE_ROTATE_270:
291 : 0 : tmp = *r;
292 : 0 : r->x1 = height - tmp.y2;
293 : 0 : r->x2 = height - tmp.y1;
294 : 0 : r->y1 = tmp.x1;
295 : 0 : r->y2 = tmp.x2;
296 : 0 : break;
297 : : default:
298 : : break;
299 : : }
300 : 0 : }
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 : 0 : void drm_rect_rotate_inv(struct drm_rect *r,
328 : : int width, int height,
329 : : unsigned int rotation)
330 : : {
331 : 0 : struct drm_rect tmp;
332 : :
333 [ # # # # ]: 0 : switch (rotation & DRM_MODE_ROTATE_MASK) {
334 : : case DRM_MODE_ROTATE_0:
335 : : break;
336 : 0 : case DRM_MODE_ROTATE_90:
337 : 0 : tmp = *r;
338 : 0 : r->x1 = width - tmp.y2;
339 : 0 : r->x2 = width - tmp.y1;
340 : 0 : r->y1 = tmp.x1;
341 : 0 : r->y2 = tmp.x2;
342 : 0 : break;
343 : 0 : case DRM_MODE_ROTATE_180:
344 : 0 : tmp = *r;
345 : 0 : r->x1 = width - tmp.x2;
346 : 0 : r->x2 = width - tmp.x1;
347 : 0 : r->y1 = height - tmp.y2;
348 : 0 : r->y2 = height - tmp.y1;
349 : 0 : break;
350 : 0 : case DRM_MODE_ROTATE_270:
351 : 0 : tmp = *r;
352 : 0 : r->x1 = tmp.y1;
353 : 0 : r->x2 = tmp.y2;
354 : 0 : r->y1 = height - tmp.x2;
355 : 0 : r->y2 = height - tmp.x1;
356 : 0 : break;
357 : : default:
358 : : break;
359 : : }
360 : :
361 [ # # ]: 0 : if (rotation & (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y)) {
362 : 0 : tmp = *r;
363 : :
364 [ # # ]: 0 : if (rotation & DRM_MODE_REFLECT_X) {
365 : 0 : r->x1 = width - tmp.x2;
366 : 0 : r->x2 = width - tmp.x1;
367 : : }
368 : :
369 [ # # ]: 0 : if (rotation & DRM_MODE_REFLECT_Y) {
370 : 0 : r->y1 = height - tmp.y2;
371 : 0 : r->y2 = height - tmp.y1;
372 : : }
373 : : }
374 : 0 : }
375 : : EXPORT_SYMBOL(drm_rect_rotate_inv);
|