Add patch that contain Mali fixes.
[deb_xorg-server.git] / randr / rrtransform.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2007 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "rrtransform.h"
25
26void
27RRTransformInit(RRTransformPtr transform)
28{
29 pixman_transform_init_identity(&transform->transform);
30 pixman_f_transform_init_identity(&transform->f_transform);
31 pixman_f_transform_init_identity(&transform->f_inverse);
32 transform->filter = NULL;
33 transform->params = NULL;
34 transform->nparams = 0;
35}
36
37void
38RRTransformFini(RRTransformPtr transform)
39{
40 free(transform->params);
41}
42
43Bool
44RRTransformEqual(RRTransformPtr a, RRTransformPtr b)
45{
46 if (a && pixman_transform_is_identity(&a->transform))
47 a = NULL;
48 if (b && pixman_transform_is_identity(&b->transform))
49 b = NULL;
50 if (a == NULL && b == NULL)
51 return TRUE;
52 if (a == NULL || b == NULL)
53 return FALSE;
54 if (memcmp(&a->transform, &b->transform, sizeof(a->transform)) != 0)
55 return FALSE;
56 if (a->filter != b->filter)
57 return FALSE;
58 if (a->nparams != b->nparams)
59 return FALSE;
60 if (memcmp(a->params, b->params, a->nparams * sizeof(xFixed)) != 0)
61 return FALSE;
62 return TRUE;
63}
64
65Bool
66RRTransformSetFilter(RRTransformPtr dst,
67 PictFilterPtr filter,
68 xFixed * params, int nparams, int width, int height)
69{
70 xFixed *new_params;
71
72 if (nparams) {
73 new_params = malloc(nparams * sizeof(xFixed));
74 if (!new_params)
75 return FALSE;
76 memcpy(new_params, params, nparams * sizeof(xFixed));
77 }
78 else
79 new_params = NULL;
80 free(dst->params);
81 dst->filter = filter;
82 dst->params = new_params;
83 dst->nparams = nparams;
84 dst->width = width;
85 dst->height = height;
86 return TRUE;
87}
88
89Bool
90RRTransformCopy(RRTransformPtr dst, RRTransformPtr src)
91{
92 if (src && pixman_transform_is_identity(&src->transform))
93 src = NULL;
94
95 if (src) {
96 if (!RRTransformSetFilter(dst, src->filter,
97 src->params, src->nparams, src->width,
98 src->height))
99 return FALSE;
100 dst->transform = src->transform;
101 dst->f_transform = src->f_transform;
102 dst->f_inverse = src->f_inverse;
103 }
104 else {
105 if (!RRTransformSetFilter(dst, NULL, NULL, 0, 0, 0))
106 return FALSE;
107 pixman_transform_init_identity(&dst->transform);
108 pixman_f_transform_init_identity(&dst->f_transform);
109 pixman_f_transform_init_identity(&dst->f_inverse);
110 }
111 return TRUE;
112}
113
114#define F(x) IntToxFixed(x)
115
116static void
117RRTransformRescale(struct pixman_f_transform *f_transform, double limit)
118{
119 double max = 0, v, scale;
120 int i, j;
121
122 for (j = 0; j < 3; j++)
123 for (i = 0; i < 3; i++)
124 if ((v = abs(f_transform->m[j][i])) > max)
125 max = v;
126 scale = limit / max;
127 for (j = 0; j < 3; j++)
128 for (i = 0; i < 3; i++)
129 f_transform->m[j][i] *= scale;
130}
131
132/*
133 * Compute the complete transformation matrix including
134 * client-specified transform, rotation/reflection values and the crtc
135 * offset.
136 *
137 * Return TRUE if the resulting transform is not a simple translation.
138 */
139Bool
140RRTransformCompute(int x,
141 int y,
142 int width,
143 int height,
144 Rotation rotation,
145 RRTransformPtr rr_transform,
146 PictTransformPtr transform,
147 struct pixman_f_transform *f_transform,
148 struct pixman_f_transform *f_inverse)
149{
150 PictTransform t_transform, inverse;
151 struct pixman_f_transform tf_transform, tf_inverse;
152 Bool overflow = FALSE;
153
154 if (!transform)
155 transform = &t_transform;
156 if (!f_transform)
157 f_transform = &tf_transform;
158 if (!f_inverse)
159 f_inverse = &tf_inverse;
160
161 pixman_transform_init_identity(transform);
162 pixman_transform_init_identity(&inverse);
163 pixman_f_transform_init_identity(f_transform);
164 pixman_f_transform_init_identity(f_inverse);
165 if (rotation != RR_Rotate_0) {
166 double f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy;
167 double f_scale_x, f_scale_y, f_scale_dx, f_scale_dy;
168 xFixed rot_cos, rot_sin, rot_dx, rot_dy;
169 xFixed scale_x, scale_y, scale_dx, scale_dy;
170
171 /* rotation */
172 switch (rotation & 0xf) {
173 default:
174 case RR_Rotate_0:
175 f_rot_cos = 1;
176 f_rot_sin = 0;
177 f_rot_dx = 0;
178 f_rot_dy = 0;
179 rot_cos = F(1);
180 rot_sin = F(0);
181 rot_dx = F(0);
182 rot_dy = F(0);
183 break;
184 case RR_Rotate_90:
185 f_rot_cos = 0;
186 f_rot_sin = 1;
187 f_rot_dx = height;
188 f_rot_dy = 0;
189 rot_cos = F(0);
190 rot_sin = F(1);
191 rot_dx = F(height);
192 rot_dy = F(0);
193 break;
194 case RR_Rotate_180:
195 f_rot_cos = -1;
196 f_rot_sin = 0;
197 f_rot_dx = width;
198 f_rot_dy = height;
199 rot_cos = F(-1);
200 rot_sin = F(0);
201 rot_dx = F(width);
202 rot_dy = F(height);
203 break;
204 case RR_Rotate_270:
205 f_rot_cos = 0;
206 f_rot_sin = -1;
207 f_rot_dx = 0;
208 f_rot_dy = width;
209 rot_cos = F(0);
210 rot_sin = F(-1);
211 rot_dx = F(0);
212 rot_dy = F(width);
213 break;
214 }
215
216 pixman_transform_rotate(transform, &inverse, rot_cos, rot_sin);
217 pixman_transform_translate(transform, &inverse, rot_dx, rot_dy);
218 pixman_f_transform_rotate(f_transform, f_inverse, f_rot_cos, f_rot_sin);
219 pixman_f_transform_translate(f_transform, f_inverse, f_rot_dx,
220 f_rot_dy);
221
222 /* reflection */
223 f_scale_x = 1;
224 f_scale_dx = 0;
225 f_scale_y = 1;
226 f_scale_dy = 0;
227 scale_x = F(1);
228 scale_dx = 0;
229 scale_y = F(1);
230 scale_dy = 0;
231 if (rotation & RR_Reflect_X) {
232 f_scale_x = -1;
233 scale_x = F(-1);
234 if (rotation & (RR_Rotate_0 | RR_Rotate_180)) {
235 f_scale_dx = width;
236 scale_dx = F(width);
237 }
238 else {
239 f_scale_dx = height;
240 scale_dx = F(height);
241 }
242 }
243 if (rotation & RR_Reflect_Y) {
244 f_scale_y = -1;
245 scale_y = F(-1);
246 if (rotation & (RR_Rotate_0 | RR_Rotate_180)) {
247 f_scale_dy = height;
248 scale_dy = F(height);
249 }
250 else {
251 f_scale_dy = width;
252 scale_dy = F(width);
253 }
254 }
255
256 pixman_transform_scale(transform, &inverse, scale_x, scale_y);
257 pixman_f_transform_scale(f_transform, f_inverse, f_scale_x, f_scale_y);
258 pixman_transform_translate(transform, &inverse, scale_dx, scale_dy);
259 pixman_f_transform_translate(f_transform, f_inverse, f_scale_dx,
260 f_scale_dy);
261 }
262
263#ifdef RANDR_12_INTERFACE
264 if (rr_transform) {
265 if (!pixman_transform_multiply
266 (transform, &rr_transform->transform, transform))
267 overflow = TRUE;
268 pixman_f_transform_multiply(f_transform, &rr_transform->f_transform,
269 f_transform);
270 pixman_f_transform_multiply(f_inverse, f_inverse,
271 &rr_transform->f_inverse);
272 }
273#endif
274 /*
275 * Compute the class of the resulting transform
276 */
277 if (!overflow && pixman_transform_is_identity(transform)) {
278 pixman_transform_init_translate(transform, F(x), F(y));
279
280 pixman_f_transform_init_translate(f_transform, x, y);
281 pixman_f_transform_init_translate(f_inverse, -x, -y);
282 return FALSE;
283 }
284 else {
285 pixman_f_transform_translate(f_transform, f_inverse, x, y);
286 if (!pixman_transform_translate(transform, &inverse, F(x), F(y)))
287 overflow = TRUE;
288 if (overflow) {
289 struct pixman_f_transform f_scaled;
290
291 f_scaled = *f_transform;
292 RRTransformRescale(&f_scaled, 16384.0);
293 pixman_transform_from_pixman_f_transform(transform, &f_scaled);
294 }
295 return TRUE;
296 }
297}