xf86Rotate.c revision 05b261ec
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 73static void 74PictureTransformIdentity (PictTransformPtr matrix) 75{ 76 int i; 77 memset (matrix, '\0', sizeof (PictTransform)); 78 for (i = 0; i < 3; i++) 79 matrix->matrix[i][i] = F(1); 80} 81 82static Bool 83PictureTransformMultiply (PictTransformPtr dst, PictTransformPtr l, PictTransformPtr r) 84{ 85 PictTransform d; 86 int dx, dy; 87 int o; 88 89 for (dy = 0; dy < 3; dy++) 90 for (dx = 0; dx < 3; dx++) 91 { 92 xFixed_48_16 v; 93 xFixed_32_32 partial; 94 v = 0; 95 for (o = 0; o < 3; o++) 96 { 97 partial = (xFixed_32_32) l->matrix[dy][o] * (xFixed_32_32) r->matrix[o][dx]; 98 v += partial >> 16; 99 } 100 if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16) 101 return FALSE; 102 d.matrix[dy][dx] = (xFixed) v; 103 } 104 *dst = d; 105 return TRUE; 106} 107 108static void 109PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy) 110{ 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); 115} 116 117static xFixed 118fixed_inverse (xFixed x) 119{ 120 return (xFixed) ((((xFixed_48_16) F(1)) * F(1)) / x); 121} 122 123static Bool 124PictureTransformScale (PictTransformPtr forward, 125 PictTransformPtr reverse, 126 xFixed sx, xFixed sy) 127{ 128 PictTransform t; 129 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; 137} 138 139static void 140PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s) 141{ 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); 148} 149 150static Bool 151PictureTransformRotate (PictTransformPtr forward, 152 PictTransformPtr reverse, 153 xFixed c, xFixed s) 154{ 155 PictTransform t; 156 PictureTransformInitRotate (&t, c, s); 157 if (!PictureTransformMultiply (forward, &t, forward)) 158 return FALSE; 159 160 PictureTransformInitRotate (&t, c, -s); 161 if (!PictureTransformMultiply (reverse, reverse, &t)) 162 return FALSE; 163 return TRUE; 164} 165 166static void 167PictureTransformInitTranslate (PictTransformPtr t, xFixed tx, xFixed ty) 168{ 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); 175} 176 177static Bool 178PictureTransformTranslate (PictTransformPtr forward, 179 PictTransformPtr reverse, 180 xFixed tx, xFixed ty) 181{ 182 PictTransform t; 183 PictureTransformInitTranslate (&t, tx, ty); 184 if (!PictureTransformMultiply (forward, &t, forward)) 185 return FALSE; 186 187 PictureTransformInitTranslate (&t, -tx, -ty); 188 if (!PictureTransformMultiply (reverse, reverse, &t)) 189 return FALSE; 190 return TRUE; 191} 192 193static void 194PictureTransformBounds (BoxPtr b, PictTransformPtr matrix) 195{ 196 PictVector v[4]; 197 int i; 198 int x1, y1, x2, y2; 199 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++) 205 { 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) 212 { 213 b->x1 = x1; b->y1 = y1; 214 b->x2 = x2; b->y2 = y2; 215 } 216 else 217 { 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; 222 } 223 } 224} 225 226static Bool 227PictureTransformIsIdentity(PictTransform *t) 228{ 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)); 238} 239 240#define toF(x) ((float) (x) / 65536.0f) 241 242static void 243PictureTransformErrorF (PictTransform *t) 244{ 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])); 249} 250 251static Bool 252PictureTransformIsInverse (char *where, PictTransform *a, PictTransform *b) 253{ 254 PictTransform t; 255 256 PictureTransformMultiply (&t, a, b); 257 if (!PictureTransformIsIdentity (&t)) 258 { 259 ErrorF ("%s: ", where); 260 PictureTransformErrorF (a); 261 ErrorF (" * "); 262 PictureTransformErrorF (b); 263 ErrorF (" = "); 264 PictureTransformErrorF (a); 265 ErrorF ("\n"); 266 return FALSE; 267 } 268 return TRUE; 269} 270 271static void 272xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) 273{ 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; 284 285 src = CreatePicture (None, 286 &root->drawable, 287 format, 288 CPSubwindowMode, 289 &include_inferiors, 290 serverClient, 291 &error); 292 if (!src) 293 return; 294 295 dst = CreatePicture (None, 296 &dst_pixmap->drawable, 297 format, 298 0L, 299 NULL, 300 serverClient, 301 &error); 302 if (!dst) 303 return; 304 305 error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); 306 if (error) 307 return; 308 309 while (n--) 310 { 311 BoxRec dst_box; 312 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++; 321 } 322 FreePicture (src, None); 323 FreePicture (dst, None); 324} 325 326static void 327xf86CrtcDamageShadow (xf86CrtcPtr crtc) 328{ 329 ScrnInfoPtr pScrn = crtc->scrn; 330 BoxRec damage_box; 331 RegionRec damage_region; 332 ScreenPtr pScreen = pScrn->pScreen; 333 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); 342} 343 344static void 345xf86RotatePrepare (ScreenPtr pScreen) 346{ 347 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 348 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 349 int c; 350 351 for (c = 0; c < xf86_config->num_crtc; c++) 352 { 353 xf86CrtcPtr crtc = xf86_config->crtc[c]; 354 355 if (crtc->rotatedData && !crtc->rotatedPixmap) 356 { 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) 362 { 363 /* Hook damage to screen pixmap */ 364 DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 365 xf86_config->rotation_damage); 366 xf86_config->rotation_damage_registered = TRUE; 367 } 368 369 xf86CrtcDamageShadow (crtc); 370 } 371 } 372} 373 374static Bool 375xf86RotateRedisplay(ScreenPtr pScreen) 376{ 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; 381 382 if (!damage) 383 return FALSE; 384 xf86RotatePrepare (pScreen); 385 region = DamageRegion(damage); 386 if (REGION_NOTEMPTY(pScreen, region)) 387 { 388 int c; 389 SourceValidateProcPtr SourceValidate; 390 391 /* 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 396 */ 397 SourceValidate = pScreen->SourceValidate; 398 pScreen->SourceValidate = NULL; 399 400 for (c = 0; c < xf86_config->num_crtc; c++) 401 { 402 xf86CrtcPtr crtc = xf86_config->crtc[c]; 403 404 if (crtc->rotation != RR_Rotate_0 && crtc->enabled) 405 { 406 RegionRec crtc_damage; 407 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); 411 412 /* update damaged region */ 413 if (REGION_NOTEMPTY(pScreen, &crtc_damage)) 414 xf86RotateCrtcRedisplay (crtc, &crtc_damage); 415 416 REGION_UNINIT (pScreen, &crtc_damage); 417 } 418 } 419 pScreen->SourceValidate = SourceValidate; 420 DamageEmpty(damage); 421 } 422 return TRUE; 423} 424 425static void 426xf86RotateBlockHandler(int screenNum, pointer blockData, 427 pointer pTimeout, pointer pReadmask) 428{ 429 ScreenPtr pScreen = screenInfo.screens[screenNum]; 430 ScrnInfoPtr pScrn = xf86Screens[screenNum]; 431 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 432 433 pScreen->BlockHandler = xf86_config->BlockHandler; 434 (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 435 if (xf86RotateRedisplay(pScreen)) 436 { 437 /* Re-wrap if rotation is still happening */ 438 xf86_config->BlockHandler = pScreen->BlockHandler; 439 pScreen->BlockHandler = xf86RotateBlockHandler; 440 } 441} 442 443static void 444xf86RotateDestroy (xf86CrtcPtr crtc) 445{ 446 ScrnInfoPtr pScrn = crtc->scrn; 447 ScreenPtr pScreen = pScrn->pScreen; 448 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 449 int c; 450 451 /* Free memory from rotation */ 452 if (crtc->rotatedPixmap || crtc->rotatedData) 453 { 454 crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); 455 crtc->rotatedPixmap = NULL; 456 crtc->rotatedData = NULL; 457 } 458 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; 463 464 /* 465 * Clean up damage structures when no crtcs are rotated 466 */ 467 if (xf86_config->rotation_damage) 468 { 469 /* Free damage structure */ 470 if (xf86_config->rotation_damage_registered) 471 { 472 DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, 473 xf86_config->rotation_damage); 474 xf86_config->rotation_damage_registered = FALSE; 475 } 476 DamageDestroy (xf86_config->rotation_damage); 477 xf86_config->rotation_damage = NULL; 478 } 479} 480 481_X_EXPORT void 482xf86RotateCloseScreen (ScreenPtr screen) 483{ 484 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 485 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 486 int c; 487 488 for (c = 0; c < xf86_config->num_crtc; c++) 489 xf86RotateDestroy (xf86_config->crtc[c]); 490} 491 492_X_EXPORT Bool 493xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) 494{ 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; 499 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) 504 { 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; 509 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; 529 } 530 531 PictureTransformRotate (&crtc_to_fb, &fb_to_crtc, rot_cos, rot_sin); 532 PictureTransformIsInverse ("rotate", &crtc_to_fb, &fb_to_crtc); 533 534 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy); 535 PictureTransformIsInverse ("rotate translate", &crtc_to_fb, &fb_to_crtc); 536 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) 543 { 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); 549 } 550 if (rotation & RR_Reflect_Y) 551 { 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); 557 } 558 559 PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y); 560 PictureTransformIsInverse ("scale", &crtc_to_fb, &fb_to_crtc); 561 562 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy); 563 PictureTransformIsInverse ("scale translate", &crtc_to_fb, &fb_to_crtc); 564 565 } 566 567 /* 568 * If the untranslated transformation is the identity, 569 * disable the shadow buffer 570 */ 571 if (PictureTransformIsIdentity (&crtc_to_fb)) 572 { 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); 579 } 580 else 581 { 582 PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, F(crtc->x), F(crtc->y)); 583 PictureTransformIsInverse ("offset", &crtc_to_fb, &fb_to_crtc); 584 585 /* 586 * these are the size of the shadow pixmap, which 587 * matches the mode, not the pre-rotated copy in the 588 * frame buffer 589 */ 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; 596 597 /* Allocate memory for rotation */ 598 if (old_width != width || old_height != height) 599 { 600 if (shadow || shadowData) 601 { 602 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 603 crtc->rotatedPixmap = NULL; 604 crtc->rotatedData = NULL; 605 } 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 */ 611 } 612 else 613 { 614 /* mark shadowed area as damaged so it will be repainted */ 615 xf86CrtcDamageShadow (crtc); 616 } 617 618 if (!xf86_config->rotation_damage) 619 { 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; 626 627 /* Wrap block handler */ 628 xf86_config->BlockHandler = pScreen->BlockHandler; 629 pScreen->BlockHandler = xf86RotateBlockHandler; 630 } 631 if (0) 632 { 633 bail2: 634 if (shadow || shadowData) 635 { 636 crtc->funcs->shadow_destroy (crtc, shadow, shadowData); 637 crtc->rotatedPixmap = NULL; 638 crtc->rotatedData = NULL; 639 } 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; 647 } 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); 656 } 657 658 /* All done */ 659 return TRUE; 660} 661