First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / modes / xf86Rotate.c
blob380478f7fa4955168afbea8b0de67146081b57e1
1 /*
2 * Copyright © 2006 Keith Packard
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.
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.
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #else
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #endif
31 #include <stddef.h>
32 #include <string.h>
33 #include <stdio.h>
35 #include "xf86.h"
36 #include "xf86DDC.h"
37 #include "fb.h"
38 #include "windowstr.h"
39 #include "xf86Crtc.h"
40 #include "xf86Modes.h"
41 #include "xf86RandR12.h"
42 #include "X11/extensions/render.h"
43 #define DPMS_SERVER
44 #include "X11/extensions/dpms.h"
45 #include "X11/Xatom.h"
47 /* borrowed from composite extension, move to Render and publish? */
49 static VisualPtr
50 compGetWindowVisual (WindowPtr pWin)
52 ScreenPtr pScreen = pWin->drawable.pScreen;
53 VisualID vid = wVisual (pWin);
54 int i;
56 for (i = 0; i < pScreen->numVisuals; i++)
57 if (pScreen->visuals[i].vid == vid)
58 return &pScreen->visuals[i];
59 return 0;
62 static PictFormatPtr
63 compWindowFormat (WindowPtr pWin)
65 ScreenPtr pScreen = pWin->drawable.pScreen;
67 return PictureMatchVisual (pScreen, pWin->drawable.depth,
68 compGetWindowVisual (pWin));
71 #define F(x) IntToxFixed(x)
73 static void
74 PictureTransformIdentity (PictTransformPtr matrix)
76 int i;
77 memset (matrix, '\0', sizeof (PictTransform));
78 for (i = 0; i < 3; i++)
79 matrix->matrix[i][i] = F(1);
82 static Bool
83 PictureTransformMultiply (PictTransformPtr dst, PictTransformPtr l, PictTransformPtr r)
85 PictTransform d;
86 int dx, dy;
87 int o;
89 for (dy = 0; dy < 3; dy++)
90 for (dx = 0; dx < 3; dx++)
92 xFixed_48_16 v;
93 xFixed_32_32 partial;
94 v = 0;
95 for (o = 0; o < 3; o++)
97 partial = (xFixed_32_32) l->matrix[dy][o] * (xFixed_32_32) r->matrix[o][dx];
98 v += partial >> 16;
100 if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16)
101 return FALSE;
102 d.matrix[dy][dx] = (xFixed) v;
104 *dst = d;
105 return TRUE;
108 static void
109 PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy)
111 memset (t, '\0', sizeof (PictTransform));
112 t->matrix[0][0] = sx;
113 t->matrix[1][1] = sy;
114 t->matrix[2][2] = F (1);
117 static xFixed
118 fixed_inverse (xFixed x)
120 return (xFixed) ((((xFixed_48_16) F(1)) * F(1)) / x);
123 static Bool
124 PictureTransformScale (PictTransformPtr forward,
125 PictTransformPtr reverse,
126 xFixed sx, xFixed sy)
128 PictTransform t;
130 PictureTransformInitScale (&t, sx, sy);
131 if (!PictureTransformMultiply (forward, &t, forward))
132 return FALSE;
133 PictureTransformInitScale (&t, fixed_inverse (sx), fixed_inverse (sy));
134 if (!PictureTransformMultiply (reverse, reverse, &t))
135 return FALSE;
136 return TRUE;
139 static void
140 PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s)
142 memset (t, '\0', sizeof (PictTransform));
143 t->matrix[0][0] = c;
144 t->matrix[0][1] = -s;
145 t->matrix[1][0] = s;
146 t->matrix[1][1] = c;
147 t->matrix[2][2] = F (1);
150 static Bool
151 PictureTransformRotate (PictTransformPtr forward,
152 PictTransformPtr reverse,
153 xFixed c, xFixed s)
155 PictTransform t;
156 PictureTransformInitRotate (&t, c, s);
157 if (!PictureTransformMultiply (forward, &t, forward))
158 return FALSE;
160 PictureTransformInitRotate (&t, c, -s);
161 if (!PictureTransformMultiply (reverse, reverse, &t))
162 return FALSE;
163 return TRUE;
166 static void
167 PictureTransformInitTranslate (PictTransformPtr t, xFixed tx, xFixed ty)
169 memset (t, '\0', sizeof (PictTransform));
170 t->matrix[0][0] = F (1);
171 t->matrix[0][2] = tx;
172 t->matrix[1][1] = F (1);
173 t->matrix[1][2] = ty;
174 t->matrix[2][2] = F (1);
177 static Bool
178 PictureTransformTranslate (PictTransformPtr forward,
179 PictTransformPtr reverse,
180 xFixed tx, xFixed ty)
182 PictTransform t;
183 PictureTransformInitTranslate (&t, tx, ty);
184 if (!PictureTransformMultiply (forward, &t, forward))
185 return FALSE;
187 PictureTransformInitTranslate (&t, -tx, -ty);
188 if (!PictureTransformMultiply (reverse, reverse, &t))
189 return FALSE;
190 return TRUE;
193 static void
194 PictureTransformBounds (BoxPtr b, PictTransformPtr matrix)
196 PictVector v[4];
197 int i;
198 int x1, y1, x2, y2;
200 v[0].vector[0] = F (b->x1); v[0].vector[1] = F (b->y1); v[0].vector[2] = F(1);
201 v[1].vector[0] = F (b->x2); v[1].vector[1] = F (b->y1); v[1].vector[2] = F(1);
202 v[2].vector[0] = F (b->x2); v[2].vector[1] = F (b->y2); v[2].vector[2] = F(1);
203 v[3].vector[0] = F (b->x1); v[3].vector[1] = F (b->y2); v[3].vector[2] = F(1);
204 for (i = 0; i < 4; i++)
206 PictureTransformPoint (matrix, &v[i]);
207 x1 = xFixedToInt (v[i].vector[0]);
208 y1 = xFixedToInt (v[i].vector[1]);
209 x2 = xFixedToInt (xFixedCeil (v[i].vector[0]));
210 y2 = xFixedToInt (xFixedCeil (v[i].vector[1]));
211 if (i == 0)
213 b->x1 = x1; b->y1 = y1;
214 b->x2 = x2; b->y2 = y2;
216 else
218 if (x1 < b->x1) b->x1 = x1;
219 if (y1 < b->y1) b->y1 = y1;
220 if (x2 > b->x2) b->x2 = x2;
221 if (y2 > b->y2) b->y2 = y2;
226 static Bool
227 PictureTransformIsIdentity(PictTransform *t)
229 return ((t->matrix[0][0] == t->matrix[1][1]) &&
230 (t->matrix[0][0] == t->matrix[2][2]) &&
231 (t->matrix[0][0] != 0) &&
232 (t->matrix[0][1] == 0) &&
233 (t->matrix[0][2] == 0) &&
234 (t->matrix[1][0] == 0) &&
235 (t->matrix[1][2] == 0) &&
236 (t->matrix[2][0] == 0) &&
237 (t->matrix[2][1] == 0));
240 #define toF(x) ((float) (x) / 65536.0f)
242 static void
243 PictureTransformErrorF (PictTransform *t)
245 ErrorF ("{ { %f %f %f } { %f %f %f } { %f %f %f } }",
246 toF(t->matrix[0][0]), toF(t->matrix[0][1]), toF(t->matrix[0][2]),
247 toF(t->matrix[1][0]), toF(t->matrix[1][1]), toF(t->matrix[1][2]),
248 toF(t->matrix[2][0]), toF(t->matrix[2][1]), toF(t->matrix[2][2]));
251 static Bool
252 PictureTransformIsInverse (char *where, PictTransform *a, PictTransform *b)
254 PictTransform t;
256 PictureTransformMultiply (&t, a, b);
257 if (!PictureTransformIsIdentity (&t))
259 ErrorF ("%s: ", where);
260 PictureTransformErrorF (a);
261 ErrorF (" * ");
262 PictureTransformErrorF (b);
263 ErrorF (" = ");
264 PictureTransformErrorF (a);
265 ErrorF ("\n");
266 return FALSE;
268 return TRUE;
271 static void
272 xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
274 ScrnInfoPtr scrn = crtc->scrn;
275 ScreenPtr screen = scrn->pScreen;
276 WindowPtr root = WindowTable[screen->myNum];
277 PixmapPtr dst_pixmap = crtc->rotatedPixmap;
278 PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]);
279 int error;
280 PicturePtr src, dst;
281 int n = REGION_NUM_RECTS(region);
282 BoxPtr b = REGION_RECTS(region);
283 XID include_inferiors = IncludeInferiors;
285 src = CreatePicture (None,
286 &root->drawable,
287 format,
288 CPSubwindowMode,
289 &include_inferiors,
290 serverClient,
291 &error);
292 if (!src)
293 return;
295 dst = CreatePicture (None,
296 &dst_pixmap->drawable,
297 format,
299 NULL,
300 serverClient,
301 &error);
302 if (!dst)
303 return;
305 error = SetPictureTransform (src, &crtc->crtc_to_framebuffer);
306 if (error)
307 return;
309 while (n--)
311 BoxRec dst_box;
313 dst_box = *b;
314 PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc);
315 CompositePicture (PictOpSrc,
316 src, NULL, dst,
317 dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1,
318 dst_box.x2 - dst_box.x1,
319 dst_box.y2 - dst_box.y1);
320 b++;
322 FreePicture (src, None);
323 FreePicture (dst, None);
326 static void
327 xf86CrtcDamageShadow (xf86CrtcPtr crtc)
329 ScrnInfoPtr pScrn = crtc->scrn;
330 BoxRec damage_box;
331 RegionRec damage_region;
332 ScreenPtr pScreen = pScrn->pScreen;
334 damage_box.x1 = crtc->x;
335 damage_box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
336 damage_box.y1 = crtc->y;
337 damage_box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
338 REGION_INIT (pScreen, &damage_region, &damage_box, 1);
339 DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
340 &damage_region);
341 REGION_UNINIT (pScreen, &damage_region);
344 static void
345 xf86RotatePrepare (ScreenPtr pScreen)
347 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
348 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
349 int c;
351 for (c = 0; c < xf86_config->num_crtc; c++)
353 xf86CrtcPtr crtc = xf86_config->crtc[c];
355 if (crtc->rotatedData && !crtc->rotatedPixmap)
357 crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
358 crtc->rotatedData,
359 crtc->mode.HDisplay,
360 crtc->mode.VDisplay);
361 if (!xf86_config->rotation_damage_registered)
363 /* Hook damage to screen pixmap */
364 DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
365 xf86_config->rotation_damage);
366 xf86_config->rotation_damage_registered = TRUE;
369 xf86CrtcDamageShadow (crtc);
374 static Bool
375 xf86RotateRedisplay(ScreenPtr pScreen)
377 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
378 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
379 DamagePtr damage = xf86_config->rotation_damage;
380 RegionPtr region;
382 if (!damage)
383 return FALSE;
384 xf86RotatePrepare (pScreen);
385 region = DamageRegion(damage);
386 if (REGION_NOTEMPTY(pScreen, region))
388 int c;
389 SourceValidateProcPtr SourceValidate;
392 * SourceValidate is used by the software cursor code
393 * to pull the cursor off of the screen when reading
394 * bits from the frame buffer. Bypassing this function
395 * leaves the software cursor in place
397 SourceValidate = pScreen->SourceValidate;
398 pScreen->SourceValidate = NULL;
400 for (c = 0; c < xf86_config->num_crtc; c++)
402 xf86CrtcPtr crtc = xf86_config->crtc[c];
404 if (crtc->rotation != RR_Rotate_0 && crtc->enabled)
406 RegionRec crtc_damage;
408 /* compute portion of damage that overlaps crtc */
409 REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1);
410 REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region);
412 /* update damaged region */
413 if (REGION_NOTEMPTY(pScreen, &crtc_damage))
414 xf86RotateCrtcRedisplay (crtc, &crtc_damage);
416 REGION_UNINIT (pScreen, &crtc_damage);
419 pScreen->SourceValidate = SourceValidate;
420 DamageEmpty(damage);
422 return TRUE;
425 static void
426 xf86RotateBlockHandler(int screenNum, pointer blockData,
427 pointer pTimeout, pointer pReadmask)
429 ScreenPtr pScreen = screenInfo.screens[screenNum];
430 ScrnInfoPtr pScrn = xf86Screens[screenNum];
431 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
433 pScreen->BlockHandler = xf86_config->BlockHandler;
434 (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
435 if (xf86RotateRedisplay(pScreen))
437 /* Re-wrap if rotation is still happening */
438 xf86_config->BlockHandler = pScreen->BlockHandler;
439 pScreen->BlockHandler = xf86RotateBlockHandler;
443 static void
444 xf86RotateDestroy (xf86CrtcPtr crtc)
446 ScrnInfoPtr pScrn = crtc->scrn;
447 ScreenPtr pScreen = pScrn->pScreen;
448 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
449 int c;
451 /* Free memory from rotation */
452 if (crtc->rotatedPixmap || crtc->rotatedData)
454 crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData);
455 crtc->rotatedPixmap = NULL;
456 crtc->rotatedData = NULL;
459 for (c = 0; c < xf86_config->num_crtc; c++)
460 if (xf86_config->crtc[c]->rotatedPixmap ||
461 xf86_config->crtc[c]->rotatedData)
462 return;
465 * Clean up damage structures when no crtcs are rotated
467 if (xf86_config->rotation_damage)
469 /* Free damage structure */
470 if (xf86_config->rotation_damage_registered)
472 DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
473 xf86_config->rotation_damage);
474 xf86_config->rotation_damage_registered = FALSE;
476 DamageDestroy (xf86_config->rotation_damage);
477 xf86_config->rotation_damage = NULL;
481 _X_EXPORT void
482 xf86RotateCloseScreen (ScreenPtr screen)
484 ScrnInfoPtr scrn = xf86Screens[screen->myNum];
485 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
486 int c;
488 for (c = 0; c < xf86_config->num_crtc; c++)
489 xf86RotateDestroy (xf86_config->crtc[c]);
492 _X_EXPORT Bool
493 xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
495 ScrnInfoPtr pScrn = crtc->scrn;
496 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
497 ScreenPtr pScreen = pScrn->pScreen;
498 PictTransform crtc_to_fb, fb_to_crtc;
500 PictureTransformIdentity (&crtc_to_fb);
501 PictureTransformIdentity (&fb_to_crtc);
502 PictureTransformIsInverse ("identity", &crtc_to_fb, &fb_to_crtc);
503 if (rotation != RR_Rotate_0)
505 xFixed rot_cos, rot_sin, rot_dx, rot_dy;
506 xFixed scale_x, scale_y, scale_dx, scale_dy;
507 int mode_w = crtc->mode.HDisplay;
508 int mode_h = crtc->mode.VDisplay;
510 /* rotation */
511 switch (rotation & 0xf) {
512 default:
513 case RR_Rotate_0:
514 rot_cos = F ( 1); rot_sin = F ( 0);
515 rot_dx = F ( 0); rot_dy = F ( 0);
516 break;
517 case RR_Rotate_90:
518 rot_cos = F ( 0); rot_sin = F ( 1);
519 rot_dx = F ( mode_h); rot_dy = F (0);
520 break;
521 case RR_Rotate_180:
522 rot_cos = F (-1); rot_sin = F ( 0);
523 rot_dx = F (mode_w); rot_dy = F ( mode_h);
524 break;
525 case RR_Rotate_270:
526 rot_cos = F ( 0); rot_sin = F (-1);
527 rot_dx = F ( 0); rot_dy = F ( mode_w);
528 break;
531 PictureTransformRotate (&crtc_to_fb, &fb_to_crtc, rot_cos, rot_sin);
532 PictureTransformIsInverse ("rotate", &crtc_to_fb, &fb_to_crtc);
534 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy);
535 PictureTransformIsInverse ("rotate translate", &crtc_to_fb, &fb_to_crtc);
537 /* reflection */
538 scale_x = F (1);
539 scale_dx = 0;
540 scale_y = F (1);
541 scale_dy = 0;
542 if (rotation & RR_Reflect_X)
544 scale_x = F(-1);
545 if (rotation & (RR_Rotate_0|RR_Rotate_180))
546 scale_dx = F(mode_w);
547 else
548 scale_dx = F(mode_h);
550 if (rotation & RR_Reflect_Y)
552 scale_y = F(-1);
553 if (rotation & (RR_Rotate_0|RR_Rotate_180))
554 scale_dy = F(mode_h);
555 else
556 scale_dy = F(mode_w);
559 PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y);
560 PictureTransformIsInverse ("scale", &crtc_to_fb, &fb_to_crtc);
562 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy);
563 PictureTransformIsInverse ("scale translate", &crtc_to_fb, &fb_to_crtc);
568 * If the untranslated transformation is the identity,
569 * disable the shadow buffer
571 if (PictureTransformIsIdentity (&crtc_to_fb))
573 crtc->transform_in_use = FALSE;
574 PictureTransformInitTranslate (&crtc->crtc_to_framebuffer,
575 F (-crtc->x), F (-crtc->y));
576 PictureTransformInitTranslate (&crtc->framebuffer_to_crtc,
577 F ( crtc->x), F ( crtc->y));
578 xf86RotateDestroy (crtc);
580 else
582 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, crtc->x, crtc->y);
583 PictureTransformIsInverse ("offset", &crtc_to_fb, &fb_to_crtc);
586 * these are the size of the shadow pixmap, which
587 * matches the mode, not the pre-rotated copy in the
588 * frame buffer
590 int width = mode->HDisplay;
591 int height = mode->VDisplay;
592 void *shadowData = crtc->rotatedData;
593 PixmapPtr shadow = crtc->rotatedPixmap;
594 int old_width = shadow ? shadow->drawable.width : 0;
595 int old_height = shadow ? shadow->drawable.height : 0;
597 /* Allocate memory for rotation */
598 if (old_width != width || old_height != height)
600 if (shadow || shadowData)
602 crtc->funcs->shadow_destroy (crtc, shadow, shadowData);
603 crtc->rotatedPixmap = NULL;
604 crtc->rotatedData = NULL;
606 shadowData = crtc->funcs->shadow_allocate (crtc, width, height);
607 if (!shadowData)
608 goto bail1;
609 crtc->rotatedData = shadowData;
610 /* shadow will be damaged in xf86RotatePrepare */
612 else
614 /* mark shadowed area as damaged so it will be repainted */
615 xf86CrtcDamageShadow (crtc);
618 if (!xf86_config->rotation_damage)
620 /* Create damage structure */
621 xf86_config->rotation_damage = DamageCreate (NULL, NULL,
622 DamageReportNone,
623 TRUE, pScreen, pScreen);
624 if (!xf86_config->rotation_damage)
625 goto bail2;
627 /* Wrap block handler */
628 xf86_config->BlockHandler = pScreen->BlockHandler;
629 pScreen->BlockHandler = xf86RotateBlockHandler;
631 if (0)
633 bail2:
634 if (shadow || shadowData)
636 crtc->funcs->shadow_destroy (crtc, shadow, shadowData);
637 crtc->rotatedPixmap = NULL;
638 crtc->rotatedData = NULL;
640 bail1:
641 if (old_width && old_height)
642 crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
643 NULL,
644 old_width,
645 old_height);
646 return FALSE;
648 crtc->transform_in_use = TRUE;
649 crtc->crtc_to_framebuffer = crtc_to_fb;
650 crtc->framebuffer_to_crtc = fb_to_crtc;
651 crtc->bounds.x1 = 0;
652 crtc->bounds.x2 = crtc->mode.HDisplay;
653 crtc->bounds.y1 = 0;
654 crtc->bounds.y2 = crtc->mode.VDisplay;
655 PictureTransformBounds (&crtc->bounds, &crtc_to_fb);
658 /* All done */
659 return TRUE;