xf86Rotate.c revision 4642e01f
1/* 2 * Copyright © 2006 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#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 30 31#include <stddef.h> 32#include <string.h> 33#include <stdio.h> 34 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" 46 47/* borrowed from composite extension, move to Render and publish? */ 48 49static VisualPtr 50compGetWindowVisual (WindowPtr pWin) 51{ 52 ScreenPtr pScreen = pWin->drawable.pScreen; 53 VisualID vid = wVisual (pWin); 54 int i; 55 56 for (i = 0; i < pScreen->numVisuals; i++) 57 if (pScreen->visuals[i].vid == vid) 58 return &pScreen->visuals[i]; 59 return 0; 60} 61 62static PictFormatPtr 63compWindowFormat (WindowPtr pWin) 64{ 65 ScreenPtr pScreen = pWin->drawable.pScreen; 66 67 return PictureMatchVisual (pScreen, pWin->drawable.depth, 68 compGetWindowVisual (pWin)); 69} 70 71#define F(x) IntToxFixed(x) 72 73#define toF(x) ((float) (x) / 65536.0f) 74 75static void 76xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) 77{ 78 ScrnInfoPtr scrn = crtc->scrn; 79 ScreenPtr screen = scrn->pScreen; 80 WindowPtr root = WindowTable[screen->myNum]; 81 PixmapPtr dst_pixmap = crtc->rotatedPixmap; 82 PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); 83 int error; 84 PicturePtr src, dst; 85 int n = REGION_NUM_RECTS(region); 86 BoxPtr b = REGION_RECTS(region); 87 XID include_inferiors = IncludeInferiors; 88 89 src = CreatePicture (None, 90 &root->drawable, 91 format, 92 CPSubwindowMode, 93 &include_inferiors, 94 serverClient, 95 &error); 96 if (!src) 97 return; 98 99 dst = CreatePicture (None, 100 &dst_pixmap->drawable, 101 format, 102 0L, 103 NULL, 104 serverClient, 105 &error); 106 if (!dst) 107 return; 108 109 error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); 110 if (error) 111 return; 112 if (crtc->transform_in_use && crtc->filter) 113 SetPicturePictFilter (src, crtc->filter, 114 crtc->params, crtc->nparams); 115 116 if (crtc->shadowClear) 117 { 118 CompositePicture (PictOpSrc, 119 src, NULL, dst, 120 0, 0, 0, 0, 0, 0, 121 crtc->mode.HDisplay, crtc->mode.VDisplay); 122 crtc->shadowClear = FALSE; 123 } 124 else 125 { 126 while (n--) 127 { 128 BoxRec dst_box; 129 130 dst_box = *b; 131 dst_box.x1 -= crtc->filter_width >> 1; 132 dst_box.x2 += crtc->filter_width >> 1; 133 dst_box.y1 -= crtc->filter_height >> 1; 134 dst_box.y2 += crtc->filter_height >> 1; 135 pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &dst_box); 136 CompositePicture (PictOpSrc, 137 src, NULL, dst, 138 dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, 139 dst_box.x2 - dst_box.x1, 140 dst_box.y2 - dst_box.y1); 141 b++; 142 } 143 } 144 FreePicture (src, None); 145 FreePicture (dst, None); 146} 147 148static void 149xf86CrtcDamageShadow (xf86CrtcPtr crtc) 150{ 151 ScrnInfoPtr pScrn = crtc->scrn; 152 BoxRec damage_box; 153 RegionRec damage_region; 154 ScreenPtr pScreen = pScrn->pScreen; 155 156 damage_box.x1 = 0; 157 damage_box.x2 = crtc->mode.HDisplay; 158 damage_box.y1 = 0; 159 damage_box.y2 = crtc->mode.VDisplay; 160 if (!pixman_transform_bounds (&crtc->crtc_to_framebuffer, &damage_box)) 161 { 162 damage_box.x1 = 0; 163 damage_box.y1 = 0; 164 damage_box.x2 = pScreen->width; 165 damage_box.y2 = pScreen->height; 166 } 167 if (damage_box.x1 < 0) damage_box.x1 = 0; 168 if (damage_box.y1 < 0) damage_box.y1 = 0; 169 if (damage_box.x2 > pScreen->width) damage_box.x2 = pScreen->width; 170 if (damage_box.y2 > pScreen->height) damage_box.y2 = pScreen->height; 171 REGION_INIT (pScreen, &damage_region, &damage_box, 1); 172 DamageRegionAppend (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 173 &damage_region); 174 REGION_UNINIT (pScreen, &damage_region); 175 crtc->shadowClear = TRUE; 176} 177 178static void 179xf86RotatePrepare (ScreenPtr pScreen) 180{ 181 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 182 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 183 int c; 184 185 for (c = 0; c < xf86_config->num_crtc; c++) 186 { 187 xf86CrtcPtr crtc = xf86_config->crtc[c]; 188 189 if (crtc->rotatedData && !crtc->rotatedPixmap) 190 { 191 crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, 192 crtc->rotatedData, 193 crtc->mode.HDisplay, 194 crtc->mode.VDisplay); 195 if (!xf86_config->rotation_damage_registered) 196 { 197 /* Hook damage to screen pixmap */ 198 DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 199 xf86_config->rotation_damage); 200 xf86_config->rotation_damage_registered = TRUE; 201 } 202 203 xf86CrtcDamageShadow (crtc); 204 } 205 } 206} 207 208static Bool 209xf86RotateRedisplay(ScreenPtr pScreen) 210{ 211 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 212 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 213 DamagePtr damage = xf86_config->rotation_damage; 214 RegionPtr region; 215 216 if (!damage) 217 return FALSE; 218 xf86RotatePrepare (pScreen); 219 region = DamageRegion(damage); 220 if (REGION_NOTEMPTY(pScreen, region)) 221 { 222 int c; 223 SourceValidateProcPtr SourceValidate; 224 225 /* 226 * SourceValidate is used by the software cursor code 227 * to pull the cursor off of the screen when reading 228 * bits from the frame buffer. Bypassing this function 229 * leaves the software cursor in place 230 */ 231 SourceValidate = pScreen->SourceValidate; 232 pScreen->SourceValidate = NULL; 233 234 for (c = 0; c < xf86_config->num_crtc; c++) 235 { 236 xf86CrtcPtr crtc = xf86_config->crtc[c]; 237 238 if (crtc->transform_in_use && crtc->enabled) 239 { 240 RegionRec crtc_damage; 241 242 /* compute portion of damage that overlaps crtc */ 243 REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); 244 REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); 245 246 /* update damaged region */ 247 if (REGION_NOTEMPTY(pScreen, &crtc_damage)) 248 xf86RotateCrtcRedisplay (crtc, &crtc_damage); 249 250 REGION_UNINIT (pScreen, &crtc_damage); 251 } 252 } 253 pScreen->SourceValidate = SourceValidate; 254 DamageEmpty(damage); 255 } 256 return TRUE; 257} 258 259static void 260xf86RotateBlockHandler(int screenNum, pointer blockData, 261 pointer pTimeout, pointer pReadmask) 262{ 263 ScreenPtr pScreen = screenInfo.screens[screenNum]; 264 ScrnInfoPtr pScrn = xf86Screens[screenNum]; 265 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 266 267 pScreen->BlockHandler = xf86_config->BlockHandler; 268 (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 269 if (xf86RotateRedisplay(pScreen)) 270 { 271 /* Re-wrap if rotation is still happening */ 272 xf86_config->BlockHandler = pScreen->BlockHandler; 273 pScreen->BlockHandler = xf86RotateBlockHandler; 274 } else { 275 xf86_config->BlockHandler = NULL; 276 } 277} 278 279void 280xf86RotateDestroy (xf86CrtcPtr crtc) 281{ 282 ScrnInfoPtr pScrn = crtc->scrn; 283 ScreenPtr pScreen = pScrn->pScreen; 284 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 285 int c; 286 287 /* Free memory from rotation */ 288 if (crtc->rotatedPixmap || crtc->rotatedData) 289 { 290 crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); 291 crtc->rotatedPixmap = NULL; 292 crtc->rotatedData = NULL; 293 } 294 295 for (c = 0; c < xf86_config->num_crtc; c++) 296 if (xf86_config->crtc[c]->transform_in_use) 297 return; 298 299 /* 300 * Clean up damage structures when no crtcs are rotated 301 */ 302 if (xf86_config->rotation_damage) 303 { 304 /* Free damage structure */ 305 if (xf86_config->rotation_damage_registered) 306 { 307 DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 308 xf86_config->rotation_damage); 309 xf86_config->rotation_damage_registered = FALSE; 310 } 311 DamageDestroy (xf86_config->rotation_damage); 312 xf86_config->rotation_damage = NULL; 313 } 314} 315 316_X_EXPORT void 317xf86RotateFreeShadow(ScrnInfoPtr pScrn) 318{ 319 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 320 int c; 321 322 for (c = 0; c < config->num_crtc; c++) { 323 xf86CrtcPtr crtc = config->crtc[c]; 324 325 if (crtc->rotatedPixmap || crtc->rotatedData) { 326 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, 327 crtc->rotatedData); 328 crtc->rotatedPixmap = NULL; 329 crtc->rotatedData = NULL; 330 } 331 } 332} 333 334_X_EXPORT void 335xf86RotateCloseScreen (ScreenPtr screen) 336{ 337 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 338 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 339 int c; 340 341 for (c = 0; c < xf86_config->num_crtc; c++) 342 xf86RotateDestroy (xf86_config->crtc[c]); 343} 344 345static Bool 346xf86CrtcFitsScreen (xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb) 347{ 348 ScrnInfoPtr pScrn = crtc->scrn; 349 BoxRec b; 350 351 /* When called before PreInit, the driver is 352 * presumably doing load detect 353 */ 354 if (pScrn->virtualX == 0 || pScrn->virtualY == 0) 355 return TRUE; 356 357 b.x1 = 0; 358 b.y1 = 0; 359 b.x2 = crtc->mode.HDisplay; 360 b.y2 = crtc->mode.VDisplay; 361 if (crtc_to_fb) 362 pixman_f_transform_bounds (crtc_to_fb, &b); 363 else { 364 b.x1 += crtc->x; 365 b.y1 += crtc->y; 366 b.x2 += crtc->x; 367 b.y2 += crtc->y; 368 } 369 370 return (0 <= b.x1 && b.x2 <= pScrn->virtualX && 371 0 <= b.y1 && b.y2 <= pScrn->virtualY); 372} 373 374_X_EXPORT Bool 375xf86CrtcRotate (xf86CrtcPtr crtc) 376{ 377 ScrnInfoPtr pScrn = crtc->scrn; 378 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 379 /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */ 380 ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; 381 PictTransform crtc_to_fb; 382 struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; 383 xFixed *new_params = NULL; 384 int new_nparams = 0; 385 PictFilterPtr new_filter = NULL; 386 int new_width = 0; 387 int new_height = 0; 388 RRTransformPtr transform = NULL; 389 Bool damage = FALSE; 390 391 if (crtc->transformPresent) 392 transform = &crtc->transform; 393 394 if (!RRTransformCompute (crtc->x, crtc->y, 395 crtc->mode.HDisplay, crtc->mode.VDisplay, 396 crtc->rotation, 397 transform, 398 399 &crtc_to_fb, 400 &f_crtc_to_fb, 401 &f_fb_to_crtc) && 402 xf86CrtcFitsScreen (crtc, &f_crtc_to_fb)) 403 { 404 /* 405 * If the untranslated transformation is the identity, 406 * disable the shadow buffer 407 */ 408 xf86RotateDestroy (crtc); 409 crtc->transform_in_use = FALSE; 410 if (new_params) 411 xfree (new_params); 412 new_params = NULL; 413 new_nparams = 0; 414 new_filter = NULL; 415 new_width = 0; 416 new_height = 0; 417 } 418 else 419 { 420 /* 421 * these are the size of the shadow pixmap, which 422 * matches the mode, not the pre-rotated copy in the 423 * frame buffer 424 */ 425 int width = crtc->mode.HDisplay; 426 int height = crtc->mode.VDisplay; 427 void *shadowData = crtc->rotatedData; 428 PixmapPtr shadow = crtc->rotatedPixmap; 429 int old_width = shadow ? shadow->drawable.width : 0; 430 int old_height = shadow ? shadow->drawable.height : 0; 431 432 /* Allocate memory for rotation */ 433 if (old_width != width || old_height != height) 434 { 435 if (shadow || shadowData) 436 { 437 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 438 crtc->rotatedPixmap = NULL; 439 crtc->rotatedData = NULL; 440 } 441 shadowData = crtc->funcs->shadow_allocate (crtc, width, height); 442 if (!shadowData) 443 goto bail1; 444 crtc->rotatedData = shadowData; 445 /* shadow will be damaged in xf86RotatePrepare */ 446 } 447 else 448 { 449 /* mark shadowed area as damaged so it will be repainted */ 450 damage = TRUE; 451 } 452 453 if (!xf86_config->rotation_damage) 454 { 455 /* Create damage structure */ 456 xf86_config->rotation_damage = DamageCreate (NULL, NULL, 457 DamageReportNone, 458 TRUE, pScreen, pScreen); 459 if (!xf86_config->rotation_damage) 460 goto bail2; 461 462 /* Wrap block handler */ 463 if (!xf86_config->BlockHandler) { 464 xf86_config->BlockHandler = pScreen->BlockHandler; 465 pScreen->BlockHandler = xf86RotateBlockHandler; 466 } 467 } 468#ifdef RANDR_12_INTERFACE 469 if (transform) 470 { 471 if (transform->nparams) { 472 new_params = xalloc (transform->nparams * sizeof (xFixed)); 473 if (new_params) { 474 memcpy (new_params, transform->params, 475 transform->nparams * sizeof (xFixed)); 476 new_nparams = transform->nparams; 477 new_filter = transform->filter; 478 } 479 } else 480 new_filter = transform->filter; 481 if (new_filter) 482 { 483 new_width = new_filter->width; 484 new_height = new_filter->height; 485 } 486 } 487#endif 488 489 if (0) 490 { 491 bail2: 492 if (shadow || shadowData) 493 { 494 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 495 crtc->rotatedPixmap = NULL; 496 crtc->rotatedData = NULL; 497 } 498 bail1: 499 if (old_width && old_height) 500 crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, 501 NULL, 502 old_width, 503 old_height); 504 return FALSE; 505 } 506 crtc->transform_in_use = TRUE; 507 } 508 crtc->crtc_to_framebuffer = crtc_to_fb; 509 crtc->f_crtc_to_framebuffer = f_crtc_to_fb; 510 crtc->f_framebuffer_to_crtc = f_fb_to_crtc; 511 if (crtc->params) 512 xfree (crtc->params); 513 crtc->params = new_params; 514 crtc->nparams = new_nparams; 515 crtc->filter = new_filter; 516 crtc->filter_width = new_width; 517 crtc->filter_height = new_height; 518 crtc->bounds.x1 = 0; 519 crtc->bounds.x2 = crtc->mode.HDisplay; 520 crtc->bounds.y1 = 0; 521 crtc->bounds.y2 = crtc->mode.VDisplay; 522 pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds); 523 524 if (damage) 525 xf86CrtcDamageShadow (crtc); 526 527 /* All done */ 528 return TRUE; 529} 530