2 * Copyright © 2006 Keith Packard
3 * Copyright © 2011 Aaron Plattner
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
39 #include "windowstr.h"
41 #include "xf86Modes.h"
42 #include "xf86RandR12.h"
43 #include "X11/extensions/render.h"
44 #include "X11/extensions/dpmsconst.h"
45 #include "X11/Xatom.h"
47 /* borrowed from composite extension, move to Render and publish? */
49 #define F(x) IntToxFixed(x)
51 #define toF(x) ((float) (x) / 65536.0f)
54 xf86RotateCrtcRedisplay(xf86CrtcPtr crtc
, RegionPtr region
)
56 ScrnInfoPtr scrn
= crtc
->scrn
;
57 ScreenPtr screen
= scrn
->pScreen
;
58 WindowPtr root
= screen
->root
;
59 PixmapPtr dst_pixmap
= crtc
->rotatedPixmap
;
60 PictFormatPtr format
= PictureWindowFormat(screen
->root
);
63 int n
= RegionNumRects(region
);
64 BoxPtr b
= RegionRects(region
);
65 XID include_inferiors
= IncludeInferiors
;
67 if (crtc
->driverIsPerformingTransform
)
70 src
= CreatePicture(None
,
74 &include_inferiors
, serverClient
, &error
);
78 dst
= CreatePicture(None
,
79 &dst_pixmap
->drawable
,
80 format
, 0L, NULL
, serverClient
, &error
);
84 error
= SetPictureTransform(src
, &crtc
->crtc_to_framebuffer
);
87 if (crtc
->transform_in_use
&& crtc
->filter
)
88 SetPicturePictFilter(src
, crtc
->filter
, crtc
->params
, crtc
->nparams
);
90 if (crtc
->shadowClear
) {
91 CompositePicture(PictOpSrc
,
94 crtc
->mode
.HDisplay
, crtc
->mode
.VDisplay
);
95 crtc
->shadowClear
= FALSE
;
102 dst_box
.x1
-= crtc
->filter_width
>> 1;
103 dst_box
.x2
+= crtc
->filter_width
>> 1;
104 dst_box
.y1
-= crtc
->filter_height
>> 1;
105 dst_box
.y2
+= crtc
->filter_height
>> 1;
106 pixman_f_transform_bounds(&crtc
->f_framebuffer_to_crtc
, &dst_box
);
107 CompositePicture(PictOpSrc
,
109 dst_box
.x1
, dst_box
.y1
, 0, 0, dst_box
.x1
,
110 dst_box
.y1
, dst_box
.x2
- dst_box
.x1
,
111 dst_box
.y2
- dst_box
.y1
);
115 FreePicture(src
, None
);
116 FreePicture(dst
, None
);
120 xf86CrtcDamageShadow(xf86CrtcPtr crtc
)
122 ScrnInfoPtr pScrn
= crtc
->scrn
;
124 RegionRec damage_region
;
125 ScreenPtr pScreen
= xf86ScrnToScreen(pScrn
);
128 damage_box
.x2
= crtc
->mode
.HDisplay
;
130 damage_box
.y2
= crtc
->mode
.VDisplay
;
131 if (!pixman_transform_bounds(&crtc
->crtc_to_framebuffer
, &damage_box
)) {
134 damage_box
.x2
= pScreen
->width
;
135 damage_box
.y2
= pScreen
->height
;
137 if (damage_box
.x1
< 0)
139 if (damage_box
.y1
< 0)
141 if (damage_box
.x2
> pScreen
->width
)
142 damage_box
.x2
= pScreen
->width
;
143 if (damage_box
.y2
> pScreen
->height
)
144 damage_box
.y2
= pScreen
->height
;
145 RegionInit(&damage_region
, &damage_box
, 1);
146 DamageDamageRegion(&(*pScreen
->GetScreenPixmap
) (pScreen
)->drawable
,
148 RegionUninit(&damage_region
);
149 crtc
->shadowClear
= TRUE
;
153 xf86RotatePrepare(ScreenPtr pScreen
)
155 ScrnInfoPtr pScrn
= xf86ScreenToScrn(pScreen
);
156 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
159 for (c
= 0; c
< xf86_config
->num_crtc
; c
++) {
160 xf86CrtcPtr crtc
= xf86_config
->crtc
[c
];
162 if (crtc
->rotatedData
&& !crtc
->rotatedPixmap
) {
163 crtc
->rotatedPixmap
= crtc
->funcs
->shadow_create(crtc
,
169 if (!xf86_config
->rotation_damage_registered
) {
170 /* Hook damage to screen pixmap */
171 DamageRegister(&pScreen
->root
->drawable
,
172 xf86_config
->rotation_damage
);
173 xf86_config
->rotation_damage_registered
= TRUE
;
174 EnableLimitedSchedulingLatency();
177 xf86CrtcDamageShadow(crtc
);
183 xf86RotateRedisplay(ScreenPtr pScreen
)
185 ScrnInfoPtr pScrn
= xf86ScreenToScrn(pScreen
);
186 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
187 DamagePtr damage
= xf86_config
->rotation_damage
;
192 xf86RotatePrepare(pScreen
);
193 region
= DamageRegion(damage
);
194 if (RegionNotEmpty(region
)) {
196 SourceValidateProcPtr SourceValidate
;
199 * SourceValidate is used by the software cursor code
200 * to pull the cursor off of the screen when reading
201 * bits from the frame buffer. Bypassing this function
202 * leaves the software cursor in place
204 SourceValidate
= pScreen
->SourceValidate
;
205 pScreen
->SourceValidate
= NULL
;
207 for (c
= 0; c
< xf86_config
->num_crtc
; c
++) {
208 xf86CrtcPtr crtc
= xf86_config
->crtc
[c
];
210 if (crtc
->transform_in_use
&& crtc
->enabled
) {
211 RegionRec crtc_damage
;
213 /* compute portion of damage that overlaps crtc */
214 RegionInit(&crtc_damage
, &crtc
->bounds
, 1);
215 RegionIntersect(&crtc_damage
, &crtc_damage
, region
);
217 /* update damaged region */
218 if (RegionNotEmpty(&crtc_damage
))
219 xf86RotateCrtcRedisplay(crtc
, &crtc_damage
);
221 RegionUninit(&crtc_damage
);
224 pScreen
->SourceValidate
= SourceValidate
;
231 xf86RotateBlockHandler(ScreenPtr pScreen
,
232 pointer pTimeout
, pointer pReadmask
)
234 ScrnInfoPtr pScrn
= xf86ScreenToScrn(pScreen
);
235 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
236 Bool rotation_active
;
238 rotation_active
= xf86RotateRedisplay(pScreen
);
239 pScreen
->BlockHandler
= xf86_config
->BlockHandler
;
240 (*pScreen
->BlockHandler
) (pScreen
, pTimeout
, pReadmask
);
241 /* cannot avoid re-wrapping until all wrapping is audited */
242 xf86_config
->BlockHandler
= pScreen
->BlockHandler
;
243 pScreen
->BlockHandler
= xf86RotateBlockHandler
;
247 xf86RotateDestroy(xf86CrtcPtr crtc
)
249 ScrnInfoPtr pScrn
= crtc
->scrn
;
250 ScreenPtr pScreen
= xf86ScrnToScreen(pScrn
);
251 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
254 /* Free memory from rotation */
255 if (crtc
->rotatedPixmap
|| crtc
->rotatedData
) {
256 crtc
->funcs
->shadow_destroy(crtc
, crtc
->rotatedPixmap
,
258 crtc
->rotatedPixmap
= NULL
;
259 crtc
->rotatedData
= NULL
;
262 for (c
= 0; c
< xf86_config
->num_crtc
; c
++)
263 if (xf86_config
->crtc
[c
]->rotatedData
)
267 * Clean up damage structures when no crtcs are rotated
269 if (xf86_config
->rotation_damage
) {
270 DrawablePtr screenDrawable
= NULL
;
271 if (pScreen
&& pScreen
->root
)
272 screenDrawable
= &pScreen
->root
->drawable
;
273 /* Free damage structure */
274 if (xf86_config
->rotation_damage_registered
) {
275 xf86_config
->rotation_damage_registered
= FALSE
;
276 DisableLimitedSchedulingLatency();
278 DamageDestroy(xf86_config
->rotation_damage
);
279 xf86_config
->rotation_damage
= NULL
;
284 xf86RotateFreeShadow(ScrnInfoPtr pScrn
)
286 xf86CrtcConfigPtr config
= XF86_CRTC_CONFIG_PTR(pScrn
);
289 for (c
= 0; c
< config
->num_crtc
; c
++) {
290 xf86CrtcPtr crtc
= config
->crtc
[c
];
292 if (crtc
->rotatedPixmap
|| crtc
->rotatedData
) {
293 crtc
->funcs
->shadow_destroy(crtc
, crtc
->rotatedPixmap
,
295 crtc
->rotatedPixmap
= NULL
;
296 crtc
->rotatedData
= NULL
;
302 xf86RotateCloseScreen(ScreenPtr screen
)
304 ScrnInfoPtr scrn
= xf86ScreenToScrn(screen
);
305 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(scrn
);
308 for (c
= 0; c
< xf86_config
->num_crtc
; c
++)
309 xf86RotateDestroy(xf86_config
->crtc
[c
]);
313 xf86CrtcFitsScreen(xf86CrtcPtr crtc
, struct pict_f_transform
*crtc_to_fb
)
315 ScrnInfoPtr pScrn
= crtc
->scrn
;
318 /* When called before PreInit, the driver is
319 * presumably doing load detect
322 ScreenPtr pScreen
= xf86ScrnToScreen(pScrn
);
323 if (pScreen
->current_master
)
324 pScrn
= xf86ScreenToScrn(pScreen
->current_master
);
327 if (pScrn
->virtualX
== 0 || pScrn
->virtualY
== 0)
332 b
.x2
= crtc
->mode
.HDisplay
;
333 b
.y2
= crtc
->mode
.VDisplay
;
335 pixman_f_transform_bounds(crtc_to_fb
, &b
);
343 return (0 <= b
.x1
&& b
.x2
<= pScrn
->virtualX
&&
344 0 <= b
.y1
&& b
.y2
<= pScrn
->virtualY
);
348 xf86CrtcRotate(xf86CrtcPtr crtc
)
350 ScrnInfoPtr pScrn
= crtc
->scrn
;
351 xf86CrtcConfigPtr xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
352 ScreenPtr pScreen
= xf86ScrnToScreen(pScrn
);
353 PictTransform crtc_to_fb
;
354 struct pict_f_transform f_crtc_to_fb
, f_fb_to_crtc
;
355 xFixed
*new_params
= NULL
;
357 PictFilterPtr new_filter
= NULL
;
360 RRTransformPtr transform
= NULL
;
363 if (crtc
->transformPresent
)
364 transform
= &crtc
->transform
;
366 if (!RRTransformCompute(crtc
->x
, crtc
->y
,
367 crtc
->mode
.HDisplay
, crtc
->mode
.VDisplay
,
373 xf86CrtcFitsScreen(crtc
, &f_crtc_to_fb
)) {
375 * If the untranslated transformation is the identity,
376 * disable the shadow buffer
378 xf86RotateDestroy(crtc
);
379 crtc
->transform_in_use
= FALSE
;
388 if (crtc
->driverIsPerformingTransform
) {
389 xf86RotateDestroy(crtc
);
393 * these are the size of the shadow pixmap, which
394 * matches the mode, not the pre-rotated copy in the
397 int width
= crtc
->mode
.HDisplay
;
398 int height
= crtc
->mode
.VDisplay
;
399 void *shadowData
= crtc
->rotatedData
;
400 PixmapPtr shadow
= crtc
->rotatedPixmap
;
401 int old_width
= shadow
? shadow
->drawable
.width
: 0;
402 int old_height
= shadow
? shadow
->drawable
.height
: 0;
404 /* Allocate memory for rotation */
405 if (old_width
!= width
|| old_height
!= height
) {
406 if (shadow
|| shadowData
) {
407 crtc
->funcs
->shadow_destroy(crtc
, shadow
, shadowData
);
408 crtc
->rotatedPixmap
= NULL
;
409 crtc
->rotatedData
= NULL
;
411 shadowData
= crtc
->funcs
->shadow_allocate(crtc
, width
, height
);
414 crtc
->rotatedData
= shadowData
;
415 /* shadow will be damaged in xf86RotatePrepare */
418 /* mark shadowed area as damaged so it will be repainted */
422 if (!xf86_config
->rotation_damage
) {
423 /* Create damage structure */
424 xf86_config
->rotation_damage
= DamageCreate(NULL
, NULL
,
428 if (!xf86_config
->rotation_damage
)
431 /* Wrap block handler */
432 if (!xf86_config
->BlockHandler
) {
433 xf86_config
->BlockHandler
= pScreen
->BlockHandler
;
434 pScreen
->BlockHandler
= xf86RotateBlockHandler
;
440 if (shadow
|| shadowData
) {
441 crtc
->funcs
->shadow_destroy(crtc
, shadow
, shadowData
);
442 crtc
->rotatedPixmap
= NULL
;
443 crtc
->rotatedData
= NULL
;
446 if (old_width
&& old_height
)
447 crtc
->rotatedPixmap
=
448 crtc
->funcs
->shadow_create(crtc
, NULL
, old_width
,
453 #ifdef RANDR_12_INTERFACE
455 if (transform
->nparams
) {
456 new_params
= malloc(transform
->nparams
* sizeof(xFixed
));
458 memcpy(new_params
, transform
->params
,
459 transform
->nparams
* sizeof(xFixed
));
460 new_nparams
= transform
->nparams
;
461 new_filter
= transform
->filter
;
465 new_filter
= transform
->filter
;
467 new_width
= new_filter
->width
;
468 new_height
= new_filter
->height
;
472 crtc
->transform_in_use
= TRUE
;
474 crtc
->crtc_to_framebuffer
= crtc_to_fb
;
475 crtc
->f_crtc_to_framebuffer
= f_crtc_to_fb
;
476 crtc
->f_framebuffer_to_crtc
= f_fb_to_crtc
;
478 crtc
->params
= new_params
;
479 crtc
->nparams
= new_nparams
;
480 crtc
->filter
= new_filter
;
481 crtc
->filter_width
= new_width
;
482 crtc
->filter_height
= new_height
;
484 crtc
->bounds
.x2
= crtc
->mode
.HDisplay
;
486 crtc
->bounds
.y2
= crtc
->mode
.VDisplay
;
487 pixman_f_transform_bounds(&f_crtc_to_fb
, &crtc
->bounds
);
490 xf86CrtcDamageShadow(crtc
);