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
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
38 #include "windowstr.h"
40 #include "xf86Modes.h"
41 #include "xf86RandR12.h"
42 #include "X11/extensions/render.h"
44 #include "X11/extensions/dpms.h"
45 #include "X11/Xatom.h"
47 /* borrowed from composite extension, move to Render and publish? */
50 compGetWindowVisual (WindowPtr pWin
)
52 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
53 VisualID vid
= wVisual (pWin
);
56 for (i
= 0; i
< pScreen
->numVisuals
; i
++)
57 if (pScreen
->visuals
[i
].vid
== vid
)
58 return &pScreen
->visuals
[i
];
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)
74 PictureTransformIdentity (PictTransformPtr matrix
)
77 memset (matrix
, '\0', sizeof (PictTransform
));
78 for (i
= 0; i
< 3; i
++)
79 matrix
->matrix
[i
][i
] = F(1);
83 PictureTransformMultiply (PictTransformPtr dst
, PictTransformPtr l
, PictTransformPtr r
)
89 for (dy
= 0; dy
< 3; dy
++)
90 for (dx
= 0; dx
< 3; dx
++)
95 for (o
= 0; o
< 3; o
++)
97 partial
= (xFixed_32_32
) l
->matrix
[dy
][o
] * (xFixed_32_32
) r
->matrix
[o
][dx
];
100 if (v
> MAX_FIXED_48_16
|| v
< MIN_FIXED_48_16
)
102 d
.matrix
[dy
][dx
] = (xFixed
) v
;
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);
118 fixed_inverse (xFixed x
)
120 return (xFixed
) ((((xFixed_48_16
) F(1)) * F(1)) / x
);
124 PictureTransformScale (PictTransformPtr forward
,
125 PictTransformPtr reverse
,
126 xFixed sx
, xFixed sy
)
130 PictureTransformInitScale (&t
, sx
, sy
);
131 if (!PictureTransformMultiply (forward
, &t
, forward
))
133 PictureTransformInitScale (&t
, fixed_inverse (sx
), fixed_inverse (sy
));
134 if (!PictureTransformMultiply (reverse
, reverse
, &t
))
140 PictureTransformInitRotate (PictTransformPtr t
, xFixed c
, xFixed s
)
142 memset (t
, '\0', sizeof (PictTransform
));
144 t
->matrix
[0][1] = -s
;
147 t
->matrix
[2][2] = F (1);
151 PictureTransformRotate (PictTransformPtr forward
,
152 PictTransformPtr reverse
,
156 PictureTransformInitRotate (&t
, c
, s
);
157 if (!PictureTransformMultiply (forward
, &t
, forward
))
160 PictureTransformInitRotate (&t
, c
, -s
);
161 if (!PictureTransformMultiply (reverse
, reverse
, &t
))
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);
178 PictureTransformTranslate (PictTransformPtr forward
,
179 PictTransformPtr reverse
,
180 xFixed tx
, xFixed ty
)
183 PictureTransformInitTranslate (&t
, tx
, ty
);
184 if (!PictureTransformMultiply (forward
, &t
, forward
))
187 PictureTransformInitTranslate (&t
, -tx
, -ty
);
188 if (!PictureTransformMultiply (reverse
, reverse
, &t
))
194 PictureTransformBounds (BoxPtr b
, PictTransformPtr matrix
)
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]));
213 b
->x1
= x1
; b
->y1
= y1
;
214 b
->x2
= x2
; b
->y2
= y2
;
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
;
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)
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]));
252 PictureTransformIsInverse (char *where
, PictTransform
*a
, PictTransform
*b
)
256 PictureTransformMultiply (&t
, a
, b
);
257 if (!PictureTransformIsIdentity (&t
))
259 ErrorF ("%s: ", where
);
260 PictureTransformErrorF (a
);
262 PictureTransformErrorF (b
);
264 PictureTransformErrorF (a
);
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
]);
281 int n
= REGION_NUM_RECTS(region
);
282 BoxPtr b
= REGION_RECTS(region
);
283 XID include_inferiors
= IncludeInferiors
;
285 src
= CreatePicture (None
,
295 dst
= CreatePicture (None
,
296 &dst_pixmap
->drawable
,
305 error
= SetPictureTransform (src
, &crtc
->crtc_to_framebuffer
);
314 PictureTransformBounds (&dst_box
, &crtc
->framebuffer_to_crtc
);
315 CompositePicture (PictOpSrc
,
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
);
322 FreePicture (src
, None
);
323 FreePicture (dst
, None
);
327 xf86CrtcDamageShadow (xf86CrtcPtr crtc
)
329 ScrnInfoPtr pScrn
= crtc
->scrn
;
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
,
341 REGION_UNINIT (pScreen
, &damage_region
);
345 xf86RotatePrepare (ScreenPtr pScreen
)
347 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
348 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
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
,
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
);
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
;
384 xf86RotatePrepare (pScreen
);
385 region
= DamageRegion(damage
);
386 if (REGION_NOTEMPTY(pScreen
, region
))
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
;
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
;
444 xf86RotateDestroy (xf86CrtcPtr crtc
)
446 ScrnInfoPtr pScrn
= crtc
->scrn
;
447 ScreenPtr pScreen
= pScrn
->pScreen
;
448 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
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
)
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
;
482 xf86RotateCloseScreen (ScreenPtr screen
)
484 ScrnInfoPtr scrn
= xf86Screens
[screen
->myNum
];
485 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(scrn
);
488 for (c
= 0; c
< xf86_config
->num_crtc
; c
++)
489 xf86RotateDestroy (xf86_config
->crtc
[c
]);
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
;
511 switch (rotation
& 0xf) {
514 rot_cos
= F ( 1); rot_sin
= F ( 0);
515 rot_dx
= F ( 0); rot_dy
= F ( 0);
518 rot_cos
= F ( 0); rot_sin
= F ( 1);
519 rot_dx
= F ( mode_h
); rot_dy
= F (0);
522 rot_cos
= F (-1); rot_sin
= F ( 0);
523 rot_dx
= F (mode_w
); rot_dy
= F ( mode_h
);
526 rot_cos
= F ( 0); rot_sin
= F (-1);
527 rot_dx
= F ( 0); rot_dy
= F ( mode_w
);
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
);
542 if (rotation
& RR_Reflect_X
)
545 if (rotation
& (RR_Rotate_0
|RR_Rotate_180
))
546 scale_dx
= F(mode_w
);
548 scale_dx
= F(mode_h
);
550 if (rotation
& RR_Reflect_Y
)
553 if (rotation
& (RR_Rotate_0
|RR_Rotate_180
))
554 scale_dy
= F(mode_h
);
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
);
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
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
);
609 crtc
->rotatedData
= shadowData
;
610 /* shadow will be damaged in xf86RotatePrepare */
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
,
623 TRUE
, pScreen
, pScreen
);
624 if (!xf86_config
->rotation_damage
)
627 /* Wrap block handler */
628 xf86_config
->BlockHandler
= pScreen
->BlockHandler
;
629 pScreen
->BlockHandler
= xf86RotateBlockHandler
;
634 if (shadow
|| shadowData
)
636 crtc
->funcs
->shadow_destroy (crtc
, shadow
, shadowData
);
637 crtc
->rotatedPixmap
= NULL
;
638 crtc
->rotatedData
= NULL
;
641 if (old_width
&& old_height
)
642 crtc
->rotatedPixmap
= crtc
->funcs
->shadow_create (crtc
,
648 crtc
->transform_in_use
= TRUE
;
649 crtc
->crtc_to_framebuffer
= crtc_to_fb
;
650 crtc
->framebuffer_to_crtc
= fb_to_crtc
;
652 crtc
->bounds
.x2
= crtc
->mode
.HDisplay
;
654 crtc
->bounds
.y2
= crtc
->mode
.VDisplay
;
655 PictureTransformBounds (&crtc
->bounds
, &crtc_to_fb
);