xf86Rotate.c revision b1d344b3
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 EnableLimitedSchedulingLatency(); 202 } 203 204 xf86CrtcDamageShadow (crtc); 205 } 206 } 207} 208 209static Bool 210xf86RotateRedisplay(ScreenPtr pScreen) 211{ 212 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 213 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 214 DamagePtr damage = xf86_config->rotation_damage; 215 RegionPtr region; 216 217 if (!damage) 218 return FALSE; 219 xf86RotatePrepare (pScreen); 220 region = DamageRegion(damage); 221 if (REGION_NOTEMPTY(pScreen, region)) 222 { 223 int c; 224 SourceValidateProcPtr SourceValidate; 225 226 /* 227 * SourceValidate is used by the software cursor code 228 * to pull the cursor off of the screen when reading 229 * bits from the frame buffer. Bypassing this function 230 * leaves the software cursor in place 231 */ 232 SourceValidate = pScreen->SourceValidate; 233 pScreen->SourceValidate = NULL; 234 235 for (c = 0; c < xf86_config->num_crtc; c++) 236 { 237 xf86CrtcPtr crtc = xf86_config->crtc[c]; 238 239 if (crtc->transform_in_use && crtc->enabled) 240 { 241 RegionRec crtc_damage; 242 243 /* compute portion of damage that overlaps crtc */ 244 REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); 245 REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); 246 247 /* update damaged region */ 248 if (REGION_NOTEMPTY(pScreen, &crtc_damage)) 249 xf86RotateCrtcRedisplay (crtc, &crtc_damage); 250 251 REGION_UNINIT (pScreen, &crtc_damage); 252 } 253 } 254 pScreen->SourceValidate = SourceValidate; 255 DamageEmpty(damage); 256 } 257 return TRUE; 258} 259 260static void 261xf86RotateBlockHandler(int screenNum, pointer blockData, 262 pointer pTimeout, pointer pReadmask) 263{ 264 ScreenPtr pScreen = screenInfo.screens[screenNum]; 265 ScrnInfoPtr pScrn = xf86Screens[screenNum]; 266 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 267 Bool rotation_active; 268 269 rotation_active = xf86RotateRedisplay(pScreen); 270 pScreen->BlockHandler = xf86_config->BlockHandler; 271 (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 272 if (rotation_active) { 273 /* Re-wrap if rotation is still happening */ 274 xf86_config->BlockHandler = pScreen->BlockHandler; 275 pScreen->BlockHandler = xf86RotateBlockHandler; 276 } else { 277 xf86_config->BlockHandler = NULL; 278 } 279} 280 281void 282xf86RotateDestroy (xf86CrtcPtr crtc) 283{ 284 ScrnInfoPtr pScrn = crtc->scrn; 285 ScreenPtr pScreen = pScrn->pScreen; 286 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 287 int c; 288 289 /* Free memory from rotation */ 290 if (crtc->rotatedPixmap || crtc->rotatedData) 291 { 292 crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); 293 crtc->rotatedPixmap = NULL; 294 crtc->rotatedData = NULL; 295 } 296 297 for (c = 0; c < xf86_config->num_crtc; c++) 298 if (xf86_config->crtc[c]->transform_in_use) 299 return; 300 301 /* 302 * Clean up damage structures when no crtcs are rotated 303 */ 304 if (xf86_config->rotation_damage) 305 { 306 /* Free damage structure */ 307 if (xf86_config->rotation_damage_registered) 308 { 309 DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 310 xf86_config->rotation_damage); 311 xf86_config->rotation_damage_registered = FALSE; 312 DisableLimitedSchedulingLatency(); 313 } 314 DamageDestroy (xf86_config->rotation_damage); 315 xf86_config->rotation_damage = NULL; 316 } 317} 318 319_X_EXPORT void 320xf86RotateFreeShadow(ScrnInfoPtr pScrn) 321{ 322 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 323 int c; 324 325 for (c = 0; c < config->num_crtc; c++) { 326 xf86CrtcPtr crtc = config->crtc[c]; 327 328 if (crtc->rotatedPixmap || crtc->rotatedData) { 329 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, 330 crtc->rotatedData); 331 crtc->rotatedPixmap = NULL; 332 crtc->rotatedData = NULL; 333 } 334 } 335} 336 337_X_EXPORT void 338xf86RotateCloseScreen (ScreenPtr screen) 339{ 340 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 341 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 342 int c; 343 344 for (c = 0; c < xf86_config->num_crtc; c++) 345 xf86RotateDestroy (xf86_config->crtc[c]); 346} 347 348static Bool 349xf86CrtcFitsScreen (xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb) 350{ 351 ScrnInfoPtr pScrn = crtc->scrn; 352 BoxRec b; 353 354 /* When called before PreInit, the driver is 355 * presumably doing load detect 356 */ 357 if (pScrn->virtualX == 0 || pScrn->virtualY == 0) 358 return TRUE; 359 360 b.x1 = 0; 361 b.y1 = 0; 362 b.x2 = crtc->mode.HDisplay; 363 b.y2 = crtc->mode.VDisplay; 364 if (crtc_to_fb) 365 pixman_f_transform_bounds (crtc_to_fb, &b); 366 else { 367 b.x1 += crtc->x; 368 b.y1 += crtc->y; 369 b.x2 += crtc->x; 370 b.y2 += crtc->y; 371 } 372 373 return (0 <= b.x1 && b.x2 <= pScrn->virtualX && 374 0 <= b.y1 && b.y2 <= pScrn->virtualY); 375} 376 377_X_EXPORT Bool 378xf86CrtcRotate (xf86CrtcPtr crtc) 379{ 380 ScrnInfoPtr pScrn = crtc->scrn; 381 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 382 /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */ 383 ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; 384 PictTransform crtc_to_fb; 385 struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; 386 xFixed *new_params = NULL; 387 int new_nparams = 0; 388 PictFilterPtr new_filter = NULL; 389 int new_width = 0; 390 int new_height = 0; 391 RRTransformPtr transform = NULL; 392 Bool damage = FALSE; 393 394 if (crtc->transformPresent) 395 transform = &crtc->transform; 396 397 if (!RRTransformCompute (crtc->x, crtc->y, 398 crtc->mode.HDisplay, crtc->mode.VDisplay, 399 crtc->rotation, 400 transform, 401 402 &crtc_to_fb, 403 &f_crtc_to_fb, 404 &f_fb_to_crtc) && 405 xf86CrtcFitsScreen (crtc, &f_crtc_to_fb)) 406 { 407 /* 408 * If the untranslated transformation is the identity, 409 * disable the shadow buffer 410 */ 411 xf86RotateDestroy (crtc); 412 crtc->transform_in_use = FALSE; 413 if (new_params) 414 xfree (new_params); 415 new_params = NULL; 416 new_nparams = 0; 417 new_filter = NULL; 418 new_width = 0; 419 new_height = 0; 420 } 421 else 422 { 423 /* 424 * these are the size of the shadow pixmap, which 425 * matches the mode, not the pre-rotated copy in the 426 * frame buffer 427 */ 428 int width = crtc->mode.HDisplay; 429 int height = crtc->mode.VDisplay; 430 void *shadowData = crtc->rotatedData; 431 PixmapPtr shadow = crtc->rotatedPixmap; 432 int old_width = shadow ? shadow->drawable.width : 0; 433 int old_height = shadow ? shadow->drawable.height : 0; 434 435 /* Allocate memory for rotation */ 436 if (old_width != width || old_height != height) 437 { 438 if (shadow || shadowData) 439 { 440 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 441 crtc->rotatedPixmap = NULL; 442 crtc->rotatedData = NULL; 443 } 444 shadowData = crtc->funcs->shadow_allocate (crtc, width, height); 445 if (!shadowData) 446 goto bail1; 447 crtc->rotatedData = shadowData; 448 /* shadow will be damaged in xf86RotatePrepare */ 449 } 450 else 451 { 452 /* mark shadowed area as damaged so it will be repainted */ 453 damage = TRUE; 454 } 455 456 if (!xf86_config->rotation_damage) 457 { 458 /* Create damage structure */ 459 xf86_config->rotation_damage = DamageCreate (NULL, NULL, 460 DamageReportNone, 461 TRUE, pScreen, pScreen); 462 if (!xf86_config->rotation_damage) 463 goto bail2; 464 465 /* Wrap block handler */ 466 if (!xf86_config->BlockHandler) { 467 xf86_config->BlockHandler = pScreen->BlockHandler; 468 pScreen->BlockHandler = xf86RotateBlockHandler; 469 } 470 } 471#ifdef RANDR_12_INTERFACE 472 if (transform) 473 { 474 if (transform->nparams) { 475 new_params = xalloc (transform->nparams * sizeof (xFixed)); 476 if (new_params) { 477 memcpy (new_params, transform->params, 478 transform->nparams * sizeof (xFixed)); 479 new_nparams = transform->nparams; 480 new_filter = transform->filter; 481 } 482 } else 483 new_filter = transform->filter; 484 if (new_filter) 485 { 486 new_width = new_filter->width; 487 new_height = new_filter->height; 488 } 489 } 490#endif 491 492 if (0) 493 { 494 bail2: 495 if (shadow || shadowData) 496 { 497 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 498 crtc->rotatedPixmap = NULL; 499 crtc->rotatedData = NULL; 500 } 501 bail1: 502 if (old_width && old_height) 503 crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, 504 NULL, 505 old_width, 506 old_height); 507 return FALSE; 508 } 509 crtc->transform_in_use = TRUE; 510 } 511 crtc->crtc_to_framebuffer = crtc_to_fb; 512 crtc->f_crtc_to_framebuffer = f_crtc_to_fb; 513 crtc->f_framebuffer_to_crtc = f_fb_to_crtc; 514 if (crtc->params) 515 xfree (crtc->params); 516 crtc->params = new_params; 517 crtc->nparams = new_nparams; 518 crtc->filter = new_filter; 519 crtc->filter_width = new_width; 520 crtc->filter_height = new_height; 521 crtc->bounds.x1 = 0; 522 crtc->bounds.x2 = crtc->mode.HDisplay; 523 crtc->bounds.y1 = 0; 524 crtc->bounds.y2 = crtc->mode.VDisplay; 525 pixman_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds); 526 527 if (damage) 528 xf86CrtcDamageShadow (crtc); 529 530 /* All done */ 531 return TRUE; 532} 533