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 : #ifdef __linux__
25 : #include <linux/errno.h>
26 : #include <linux/export.h>
27 : #include <linux/kernel.h>
28 : #endif
29 : #include <dev/pci/drm/drmP.h>
30 : #include <dev/pci/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 : /**
56 : * drm_rect_clip_scaled - perform a scaled clip operation
57 : * @src: source window rectangle
58 : * @dst: destination window rectangle
59 : * @clip: clip rectangle
60 : * @hscale: horizontal scaling factor
61 : * @vscale: vertical scaling factor
62 : *
63 : * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
64 : * same amounts multiplied by @hscale and @vscale.
65 : *
66 : * RETURNS:
67 : * %true if rectangle @dst is still visible after being clipped,
68 : * %false otherwise
69 : */
70 0 : bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
71 : const struct drm_rect *clip,
72 : int hscale, int vscale)
73 : {
74 : int diff;
75 :
76 0 : diff = clip->x1 - dst->x1;
77 0 : if (diff > 0) {
78 0 : int64_t tmp = src->x1 + (int64_t) diff * hscale;
79 0 : src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
80 0 : }
81 0 : diff = clip->y1 - dst->y1;
82 0 : if (diff > 0) {
83 0 : int64_t tmp = src->y1 + (int64_t) diff * vscale;
84 0 : src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
85 0 : }
86 0 : diff = dst->x2 - clip->x2;
87 0 : if (diff > 0) {
88 0 : int64_t tmp = src->x2 - (int64_t) diff * hscale;
89 0 : src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
90 0 : }
91 0 : diff = dst->y2 - clip->y2;
92 0 : if (diff > 0) {
93 0 : int64_t tmp = src->y2 - (int64_t) diff * vscale;
94 0 : src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
95 0 : }
96 :
97 0 : return drm_rect_intersect(dst, clip);
98 : }
99 : EXPORT_SYMBOL(drm_rect_clip_scaled);
100 :
101 0 : static int drm_calc_scale(int src, int dst)
102 : {
103 : int scale = 0;
104 :
105 0 : if (src < 0 || dst < 0)
106 0 : return -EINVAL;
107 :
108 0 : if (dst == 0)
109 0 : return 0;
110 :
111 0 : scale = src / dst;
112 :
113 0 : return scale;
114 0 : }
115 :
116 : /**
117 : * drm_rect_calc_hscale - calculate the horizontal scaling factor
118 : * @src: source window rectangle
119 : * @dst: destination window rectangle
120 : * @min_hscale: minimum allowed horizontal scaling factor
121 : * @max_hscale: maximum allowed horizontal scaling factor
122 : *
123 : * Calculate the horizontal scaling factor as
124 : * (@src width) / (@dst width).
125 : *
126 : * RETURNS:
127 : * The horizontal scaling factor, or errno of out of limits.
128 : */
129 0 : int drm_rect_calc_hscale(const struct drm_rect *src,
130 : const struct drm_rect *dst,
131 : int min_hscale, int max_hscale)
132 : {
133 0 : int src_w = drm_rect_width(src);
134 0 : int dst_w = drm_rect_width(dst);
135 0 : int hscale = drm_calc_scale(src_w, dst_w);
136 :
137 0 : if (hscale < 0 || dst_w == 0)
138 0 : return hscale;
139 :
140 0 : if (hscale < min_hscale || hscale > max_hscale)
141 0 : return -ERANGE;
142 :
143 0 : return hscale;
144 0 : }
145 : EXPORT_SYMBOL(drm_rect_calc_hscale);
146 :
147 : /**
148 : * drm_rect_calc_vscale - calculate the vertical scaling factor
149 : * @src: source window rectangle
150 : * @dst: destination window rectangle
151 : * @min_vscale: minimum allowed vertical scaling factor
152 : * @max_vscale: maximum allowed vertical scaling factor
153 : *
154 : * Calculate the vertical scaling factor as
155 : * (@src height) / (@dst height).
156 : *
157 : * RETURNS:
158 : * The vertical scaling factor, or errno of out of limits.
159 : */
160 0 : int drm_rect_calc_vscale(const struct drm_rect *src,
161 : const struct drm_rect *dst,
162 : int min_vscale, int max_vscale)
163 : {
164 0 : int src_h = drm_rect_height(src);
165 0 : int dst_h = drm_rect_height(dst);
166 0 : int vscale = drm_calc_scale(src_h, dst_h);
167 :
168 0 : if (vscale < 0 || dst_h == 0)
169 0 : return vscale;
170 :
171 0 : if (vscale < min_vscale || vscale > max_vscale)
172 0 : return -ERANGE;
173 :
174 0 : return vscale;
175 0 : }
176 : EXPORT_SYMBOL(drm_rect_calc_vscale);
177 :
178 : /**
179 : * drm_calc_hscale_relaxed - calculate the horizontal scaling factor
180 : * @src: source window rectangle
181 : * @dst: destination window rectangle
182 : * @min_hscale: minimum allowed horizontal scaling factor
183 : * @max_hscale: maximum allowed horizontal scaling factor
184 : *
185 : * Calculate the horizontal scaling factor as
186 : * (@src width) / (@dst width).
187 : *
188 : * If the calculated scaling factor is below @min_vscale,
189 : * decrease the height of rectangle @dst to compensate.
190 : *
191 : * If the calculated scaling factor is above @max_vscale,
192 : * decrease the height of rectangle @src to compensate.
193 : *
194 : * RETURNS:
195 : * The horizontal scaling factor.
196 : */
197 0 : int drm_rect_calc_hscale_relaxed(struct drm_rect *src,
198 : struct drm_rect *dst,
199 : int min_hscale, int max_hscale)
200 : {
201 0 : int src_w = drm_rect_width(src);
202 0 : int dst_w = drm_rect_width(dst);
203 0 : int hscale = drm_calc_scale(src_w, dst_w);
204 :
205 0 : if (hscale < 0 || dst_w == 0)
206 0 : return hscale;
207 :
208 0 : if (hscale < min_hscale) {
209 0 : int max_dst_w = src_w / min_hscale;
210 :
211 0 : drm_rect_adjust_size(dst, max_dst_w - dst_w, 0);
212 :
213 : return min_hscale;
214 : }
215 :
216 0 : if (hscale > max_hscale) {
217 0 : int max_src_w = dst_w * max_hscale;
218 :
219 0 : drm_rect_adjust_size(src, max_src_w - src_w, 0);
220 :
221 : return max_hscale;
222 : }
223 :
224 0 : return hscale;
225 0 : }
226 : EXPORT_SYMBOL(drm_rect_calc_hscale_relaxed);
227 :
228 : /**
229 : * drm_rect_calc_vscale_relaxed - calculate the vertical scaling factor
230 : * @src: source window rectangle
231 : * @dst: destination window rectangle
232 : * @min_vscale: minimum allowed vertical scaling factor
233 : * @max_vscale: maximum allowed vertical scaling factor
234 : *
235 : * Calculate the vertical scaling factor as
236 : * (@src height) / (@dst height).
237 : *
238 : * If the calculated scaling factor is below @min_vscale,
239 : * decrease the height of rectangle @dst to compensate.
240 : *
241 : * If the calculated scaling factor is above @max_vscale,
242 : * decrease the height of rectangle @src to compensate.
243 : *
244 : * RETURNS:
245 : * The vertical scaling factor.
246 : */
247 0 : int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
248 : struct drm_rect *dst,
249 : int min_vscale, int max_vscale)
250 : {
251 0 : int src_h = drm_rect_height(src);
252 0 : int dst_h = drm_rect_height(dst);
253 0 : int vscale = drm_calc_scale(src_h, dst_h);
254 :
255 0 : if (vscale < 0 || dst_h == 0)
256 0 : return vscale;
257 :
258 0 : if (vscale < min_vscale) {
259 0 : int max_dst_h = src_h / min_vscale;
260 :
261 0 : drm_rect_adjust_size(dst, 0, max_dst_h - dst_h);
262 :
263 : return min_vscale;
264 : }
265 :
266 0 : if (vscale > max_vscale) {
267 0 : int max_src_h = dst_h * max_vscale;
268 :
269 0 : drm_rect_adjust_size(src, 0, max_src_h - src_h);
270 :
271 : return max_vscale;
272 : }
273 :
274 0 : return vscale;
275 0 : }
276 : EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed);
277 :
278 : /**
279 : * drm_rect_debug_print - print the rectangle information
280 : * @r: rectangle to print
281 : * @fixed_point: rectangle is in 16.16 fixed point format
282 : */
283 0 : void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point)
284 : {
285 : #ifdef DRMDEBUG
286 : int w = drm_rect_width(r);
287 : int h = drm_rect_height(r);
288 :
289 : if (fixed_point)
290 : DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n",
291 : w >> 16, ((w & 0xffff) * 15625) >> 10,
292 : h >> 16, ((h & 0xffff) * 15625) >> 10,
293 : r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10,
294 : r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10);
295 : else
296 : DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1);
297 : #endif
298 0 : }
299 : EXPORT_SYMBOL(drm_rect_debug_print);
300 :
301 : /**
302 : * drm_rect_rotate - Rotate the rectangle
303 : * @r: rectangle to be rotated
304 : * @width: Width of the coordinate space
305 : * @height: Height of the coordinate space
306 : * @rotation: Transformation to be applied
307 : *
308 : * Apply @rotation to the coordinates of rectangle @r.
309 : *
310 : * @width and @height combined with @rotation define
311 : * the location of the new origin.
312 : *
313 : * @width correcsponds to the horizontal and @height
314 : * to the vertical axis of the untransformed coordinate
315 : * space.
316 : */
317 0 : void drm_rect_rotate(struct drm_rect *r,
318 : int width, int height,
319 : unsigned int rotation)
320 : {
321 : struct drm_rect tmp;
322 :
323 0 : if (rotation & (BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y))) {
324 0 : tmp = *r;
325 :
326 0 : if (rotation & BIT(DRM_REFLECT_X)) {
327 0 : r->x1 = width - tmp.x2;
328 0 : r->x2 = width - tmp.x1;
329 0 : }
330 :
331 0 : if (rotation & BIT(DRM_REFLECT_Y)) {
332 0 : r->y1 = height - tmp.y2;
333 0 : r->y2 = height - tmp.y1;
334 0 : }
335 : }
336 :
337 0 : switch (rotation & DRM_ROTATE_MASK) {
338 : case BIT(DRM_ROTATE_0):
339 : break;
340 : case BIT(DRM_ROTATE_90):
341 0 : tmp = *r;
342 0 : r->x1 = tmp.y1;
343 0 : r->x2 = tmp.y2;
344 0 : r->y1 = width - tmp.x2;
345 0 : r->y2 = width - tmp.x1;
346 0 : break;
347 : case BIT(DRM_ROTATE_180):
348 0 : tmp = *r;
349 0 : r->x1 = width - tmp.x2;
350 0 : r->x2 = width - tmp.x1;
351 0 : r->y1 = height - tmp.y2;
352 0 : r->y2 = height - tmp.y1;
353 0 : break;
354 : case BIT(DRM_ROTATE_270):
355 0 : tmp = *r;
356 0 : r->x1 = height - tmp.y2;
357 0 : r->x2 = height - tmp.y1;
358 0 : r->y1 = tmp.x1;
359 0 : r->y2 = tmp.x2;
360 0 : break;
361 : default:
362 : break;
363 : }
364 0 : }
365 : EXPORT_SYMBOL(drm_rect_rotate);
366 :
367 : /**
368 : * drm_rect_rotate_inv - Inverse rotate the rectangle
369 : * @r: rectangle to be rotated
370 : * @width: Width of the coordinate space
371 : * @height: Height of the coordinate space
372 : * @rotation: Transformation whose inverse is to be applied
373 : *
374 : * Apply the inverse of @rotation to the coordinates
375 : * of rectangle @r.
376 : *
377 : * @width and @height combined with @rotation define
378 : * the location of the new origin.
379 : *
380 : * @width correcsponds to the horizontal and @height
381 : * to the vertical axis of the original untransformed
382 : * coordinate space, so that you never have to flip
383 : * them when doing a rotatation and its inverse.
384 : * That is, if you do:
385 : *
386 : * drm_rotate(&r, width, height, rotation);
387 : * drm_rotate_inv(&r, width, height, rotation);
388 : *
389 : * you will always get back the original rectangle.
390 : */
391 0 : void drm_rect_rotate_inv(struct drm_rect *r,
392 : int width, int height,
393 : unsigned int rotation)
394 : {
395 : struct drm_rect tmp;
396 :
397 0 : switch (rotation & DRM_ROTATE_MASK) {
398 : case BIT(DRM_ROTATE_0):
399 : break;
400 : case BIT(DRM_ROTATE_90):
401 0 : tmp = *r;
402 0 : r->x1 = width - tmp.y2;
403 0 : r->x2 = width - tmp.y1;
404 0 : r->y1 = tmp.x1;
405 0 : r->y2 = tmp.x2;
406 0 : break;
407 : case BIT(DRM_ROTATE_180):
408 0 : tmp = *r;
409 0 : r->x1 = width - tmp.x2;
410 0 : r->x2 = width - tmp.x1;
411 0 : r->y1 = height - tmp.y2;
412 0 : r->y2 = height - tmp.y1;
413 0 : break;
414 : case BIT(DRM_ROTATE_270):
415 0 : tmp = *r;
416 0 : r->x1 = tmp.y1;
417 0 : r->x2 = tmp.y2;
418 0 : r->y1 = height - tmp.x2;
419 0 : r->y2 = height - tmp.x1;
420 0 : break;
421 : default:
422 : break;
423 : }
424 :
425 0 : if (rotation & (BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y))) {
426 0 : tmp = *r;
427 :
428 0 : if (rotation & BIT(DRM_REFLECT_X)) {
429 0 : r->x1 = width - tmp.x2;
430 0 : r->x2 = width - tmp.x1;
431 0 : }
432 :
433 0 : if (rotation & BIT(DRM_REFLECT_Y)) {
434 0 : r->y1 = height - tmp.y2;
435 0 : r->y2 = height - tmp.y1;
436 0 : }
437 : }
438 0 : }
439 : EXPORT_SYMBOL(drm_rect_rotate_inv);
|