1/* 2 * Copyright © 2006 Keith Packard 3 * Copyright 2010 Red Hat, Inc 4 * 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. 14 * 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 21 * OF THIS SOFTWARE. 22 */ 23 24#include "randrstr.h" 25#include "swaprep.h" 26#include "mipointer.h" 27 28#include <X11/Xatom.h> 29 30RESTYPE RRCrtcType = 0; 31 32/* 33 * Notify the CRTC of some change 34 */ 35void 36RRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged) 37{ 38 ScreenPtr pScreen = crtc->pScreen; 39 40 crtc->changed = TRUE; 41 if (pScreen) { 42 rrScrPriv(pScreen); 43 44 RRSetChanged(pScreen); 45 /* 46 * Send ConfigureNotify on any layout change 47 */ 48 if (layoutChanged) 49 pScrPriv->layoutChanged = TRUE; 50 } 51} 52 53/* 54 * Create a CRTC 55 */ 56RRCrtcPtr 57RRCrtcCreate(ScreenPtr pScreen, void *devPrivate) 58{ 59 RRCrtcPtr crtc; 60 RRCrtcPtr *crtcs; 61 rrScrPrivPtr pScrPriv; 62 63 if (!RRInit()) 64 return NULL; 65 66 pScrPriv = rrGetScrPriv(pScreen); 67 68 /* make space for the crtc pointer */ 69 crtcs = reallocarray(pScrPriv->crtcs, 70 pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr)); 71 if (!crtcs) 72 return NULL; 73 pScrPriv->crtcs = crtcs; 74 75 crtc = calloc(1, sizeof(RRCrtcRec)); 76 if (!crtc) 77 return NULL; 78 crtc->id = FakeClientID(0); 79 crtc->pScreen = pScreen; 80 crtc->mode = NULL; 81 crtc->x = 0; 82 crtc->y = 0; 83 crtc->rotation = RR_Rotate_0; 84 crtc->rotations = RR_Rotate_0; 85 crtc->outputs = NULL; 86 crtc->numOutputs = 0; 87 crtc->gammaSize = 0; 88 crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL; 89 crtc->changed = FALSE; 90 crtc->devPrivate = devPrivate; 91 RRTransformInit(&crtc->client_pending_transform); 92 RRTransformInit(&crtc->client_current_transform); 93 pixman_transform_init_identity(&crtc->transform); 94 pixman_f_transform_init_identity(&crtc->f_transform); 95 pixman_f_transform_init_identity(&crtc->f_inverse); 96 97 if (!AddResource(crtc->id, RRCrtcType, (void *) crtc)) 98 return NULL; 99 100 /* attach the screen and crtc together */ 101 crtc->pScreen = pScreen; 102 pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; 103 104 RRResourcesChanged(pScreen); 105 106 return crtc; 107} 108 109/* 110 * Set the allowed rotations on a CRTC 111 */ 112void 113RRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations) 114{ 115 crtc->rotations = rotations; 116} 117 118/* 119 * Set whether transforms are allowed on a CRTC 120 */ 121void 122RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms) 123{ 124 crtc->transforms = transforms; 125} 126 127/* 128 * Notify the extension that the Crtc has been reconfigured, 129 * the driver calls this whenever it has updated the mode 130 */ 131Bool 132RRCrtcNotify(RRCrtcPtr crtc, 133 RRModePtr mode, 134 int x, 135 int y, 136 Rotation rotation, 137 RRTransformPtr transform, int numOutputs, RROutputPtr * outputs) 138{ 139 int i, j; 140 141 /* 142 * Check to see if any of the new outputs were 143 * not in the old list and mark them as changed 144 */ 145 for (i = 0; i < numOutputs; i++) { 146 for (j = 0; j < crtc->numOutputs; j++) 147 if (outputs[i] == crtc->outputs[j]) 148 break; 149 if (j == crtc->numOutputs) { 150 outputs[i]->crtc = crtc; 151 RROutputChanged(outputs[i], FALSE); 152 RRCrtcChanged(crtc, FALSE); 153 } 154 } 155 /* 156 * Check to see if any of the old outputs are 157 * not in the new list and mark them as changed 158 */ 159 for (j = 0; j < crtc->numOutputs; j++) { 160 for (i = 0; i < numOutputs; i++) 161 if (outputs[i] == crtc->outputs[j]) 162 break; 163 if (i == numOutputs) { 164 if (crtc->outputs[j]->crtc == crtc) 165 crtc->outputs[j]->crtc = NULL; 166 RROutputChanged(crtc->outputs[j], FALSE); 167 RRCrtcChanged(crtc, FALSE); 168 } 169 } 170 /* 171 * Reallocate the crtc output array if necessary 172 */ 173 if (numOutputs != crtc->numOutputs) { 174 RROutputPtr *newoutputs; 175 176 if (numOutputs) { 177 if (crtc->numOutputs) 178 newoutputs = reallocarray(crtc->outputs, 179 numOutputs, sizeof(RROutputPtr)); 180 else 181 newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 182 if (!newoutputs) 183 return FALSE; 184 } 185 else { 186 free(crtc->outputs); 187 newoutputs = NULL; 188 } 189 crtc->outputs = newoutputs; 190 crtc->numOutputs = numOutputs; 191 } 192 /* 193 * Copy the new list of outputs into the crtc 194 */ 195 memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)); 196 /* 197 * Update remaining crtc fields 198 */ 199 if (mode != crtc->mode) { 200 if (crtc->mode) 201 RRModeDestroy(crtc->mode); 202 crtc->mode = mode; 203 if (mode != NULL) 204 mode->refcnt++; 205 RRCrtcChanged(crtc, TRUE); 206 } 207 if (x != crtc->x) { 208 crtc->x = x; 209 RRCrtcChanged(crtc, TRUE); 210 } 211 if (y != crtc->y) { 212 crtc->y = y; 213 RRCrtcChanged(crtc, TRUE); 214 } 215 if (rotation != crtc->rotation) { 216 crtc->rotation = rotation; 217 RRCrtcChanged(crtc, TRUE); 218 } 219 if (!RRTransformEqual(transform, &crtc->client_current_transform)) { 220 RRTransformCopy(&crtc->client_current_transform, transform); 221 RRCrtcChanged(crtc, TRUE); 222 } 223 if (crtc->changed && mode) { 224 RRTransformCompute(x, y, 225 mode->mode.width, mode->mode.height, 226 rotation, 227 &crtc->client_current_transform, 228 &crtc->transform, &crtc->f_transform, 229 &crtc->f_inverse); 230 } 231 return TRUE; 232} 233 234void 235RRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) 236{ 237 ScreenPtr pScreen = pWin->drawable.pScreen; 238 239 rrScrPriv(pScreen); 240 RRModePtr mode = crtc->mode; 241 242 xRRCrtcChangeNotifyEvent ce = { 243 .type = RRNotify + RREventBase, 244 .subCode = RRNotify_CrtcChange, 245 .timestamp = pScrPriv->lastSetTime.milliseconds, 246 .window = pWin->drawable.id, 247 .crtc = crtc->id, 248 .mode = mode ? mode->mode.id : None, 249 .rotation = crtc->rotation, 250 .x = mode ? crtc->x : 0, 251 .y = mode ? crtc->y : 0, 252 .width = mode ? mode->mode.width : 0, 253 .height = mode ? mode->mode.height : 0 254 }; 255 WriteEventsToClient(client, 1, (xEvent *) &ce); 256} 257 258static Bool 259RRCrtcPendingProperties(RRCrtcPtr crtc) 260{ 261 ScreenPtr pScreen = crtc->pScreen; 262 263 rrScrPriv(pScreen); 264 int o; 265 266 for (o = 0; o < pScrPriv->numOutputs; o++) { 267 RROutputPtr output = pScrPriv->outputs[o]; 268 269 if (output->crtc == crtc && output->pendingProperties) 270 return TRUE; 271 } 272 return FALSE; 273} 274 275static Bool 276cursor_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom) 277{ 278 rrScrPriv(crtc->pScreen); 279 BoxRec bounds; 280 281 if (crtc->mode == NULL) 282 return FALSE; 283 284 memset(&bounds, 0, sizeof(bounds)); 285 if (pScrPriv->rrGetPanning) 286 pScrPriv->rrGetPanning(crtc->pScreen, crtc, NULL, &bounds, NULL); 287 288 if (bounds.y2 <= bounds.y1 || bounds.x2 <= bounds.x1) { 289 bounds.x1 = 0; 290 bounds.y1 = 0; 291 bounds.x2 = crtc->mode->mode.width; 292 bounds.y2 = crtc->mode->mode.height; 293 } 294 295 pixman_f_transform_bounds(&crtc->f_transform, &bounds); 296 297 *left = bounds.x1; 298 *right = bounds.x2; 299 *top = bounds.y1; 300 *bottom = bounds.y2; 301 302 return TRUE; 303} 304 305/* overlapping counts as adjacent */ 306static Bool 307crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b) 308{ 309 /* left, right, top, bottom... */ 310 int al, ar, at, ab; 311 int bl, br, bt, bb; 312 int cl, cr, ct, cb; /* the overlap, if any */ 313 314 if (!cursor_bounds(a, &al, &ar, &at, &ab)) 315 return FALSE; 316 if (!cursor_bounds(b, &bl, &br, &bt, &bb)) 317 return FALSE; 318 319 cl = max(al, bl); 320 cr = min(ar, br); 321 ct = max(at, bt); 322 cb = min(ab, bb); 323 324 return (cl <= cr) && (ct <= cb); 325} 326 327/* Depth-first search and mark all CRTCs reachable from cur */ 328static void 329mark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur) 330{ 331 int i; 332 333 reachable[cur] = TRUE; 334 for (i = 0; i < pScrPriv->numCrtcs; ++i) { 335 if (reachable[i]) 336 continue; 337 if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i])) 338 mark_crtcs(pScrPriv, reachable, i); 339 } 340} 341 342static void 343RRComputeContiguity(ScreenPtr pScreen) 344{ 345 rrScrPriv(pScreen); 346 Bool discontiguous = TRUE; 347 int i, n = pScrPriv->numCrtcs; 348 349 int *reachable = calloc(n, sizeof(int)); 350 351 if (!reachable) 352 goto out; 353 354 /* Find first enabled CRTC and start search for reachable CRTCs from it */ 355 for (i = 0; i < n; ++i) { 356 if (pScrPriv->crtcs[i]->mode) { 357 mark_crtcs(pScrPriv, reachable, i); 358 break; 359 } 360 } 361 362 /* Check that all enabled CRTCs were marked as reachable */ 363 for (i = 0; i < n; ++i) 364 if (pScrPriv->crtcs[i]->mode && !reachable[i]) 365 goto out; 366 367 discontiguous = FALSE; 368 369 out: 370 free(reachable); 371 pScrPriv->discontiguous = discontiguous; 372} 373 374static void 375rrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) { 376 ScreenPtr primary = crtc->pScreen->current_primary; 377 378 if (primary && pPixmap->primary_pixmap) { 379 /* 380 * Unref the pixmap twice: once for the original reference, and once 381 * for the reference implicitly added by PixmapShareToSecondary. 382 */ 383 PixmapUnshareSecondaryPixmap(pPixmap); 384 385 primary->DestroyPixmap(pPixmap->primary_pixmap); 386 primary->DestroyPixmap(pPixmap->primary_pixmap); 387 } 388 389 crtc->pScreen->DestroyPixmap(pPixmap); 390} 391 392void 393RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc) 394{ 395 rrScrPriv(crtc->pScreen); 396 397 if (crtc->scanout_pixmap) { 398 ScreenPtr primary = crtc->pScreen->current_primary; 399 DrawablePtr mrootdraw = &primary->root->drawable; 400 401 if (crtc->scanout_pixmap_back) { 402 pScrPriv->rrDisableSharedPixmapFlipping(crtc); 403 404 if (mrootdraw) { 405 primary->StopFlippingPixmapTracking(mrootdraw, 406 crtc->scanout_pixmap, 407 crtc->scanout_pixmap_back); 408 } 409 410 rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back); 411 crtc->scanout_pixmap_back = NULL; 412 } 413 else { 414 pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL); 415 416 if (mrootdraw) { 417 primary->StopPixmapTracking(mrootdraw, 418 crtc->scanout_pixmap); 419 } 420 } 421 422 rrDestroySharedPixmap(crtc, crtc->scanout_pixmap); 423 crtc->scanout_pixmap = NULL; 424 } 425 426 RRCrtcChanged(crtc, TRUE); 427} 428 429static PixmapPtr 430rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr primary, 431 int width, int height, int depth, 432 int x, int y, Rotation rotation) 433{ 434 PixmapPtr mpix, spix; 435 436 mpix = primary->CreatePixmap(primary, width, height, depth, 437 CREATE_PIXMAP_USAGE_SHARED); 438 if (!mpix) 439 return NULL; 440 441 spix = PixmapShareToSecondary(mpix, crtc->pScreen); 442 if (spix == NULL) { 443 primary->DestroyPixmap(mpix); 444 return NULL; 445 } 446 447 return spix; 448} 449 450static Bool 451rrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs) 452{ 453 /* Determine if the user wants prime syncing */ 454 int o; 455 const char *syncStr = PRIME_SYNC_PROP; 456 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 457 if (syncProp == None) 458 return TRUE; 459 460 /* If one output doesn't want sync, no sync */ 461 for (o = 0; o < numOutputs; o++) { 462 RRPropertyValuePtr val; 463 464 /* Try pending value first, then current value */ 465 if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) && 466 val->data) { 467 if (!(*(char *) val->data)) 468 return FALSE; 469 continue; 470 } 471 472 if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) && 473 val->data) { 474 if (!(*(char *) val->data)) 475 return FALSE; 476 continue; 477 } 478 } 479 480 return TRUE; 481} 482 483static void 484rrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs) 485{ 486 int o; 487 const char *syncStr = PRIME_SYNC_PROP; 488 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 489 if (syncProp == None) 490 return; 491 492 for (o = 0; o < numOutputs; o++) { 493 RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp); 494 if (prop) 495 RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER, 496 8, PropModeReplace, 1, &val, FALSE, TRUE); 497 } 498} 499 500static Bool 501rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height, 502 int x, int y, Rotation rotation, Bool sync, 503 int numOutputs, RROutputPtr * outputs) 504{ 505 ScreenPtr primary = crtc->pScreen->current_primary; 506 rrScrPrivPtr pPrimaryScrPriv = rrGetScrPriv(primary); 507 rrScrPrivPtr pSecondaryScrPriv = rrGetScrPriv(crtc->pScreen); 508 DrawablePtr mrootdraw = &primary->root->drawable; 509 int depth = mrootdraw->depth; 510 PixmapPtr spix_front; 511 512 /* Create a pixmap on the primary screen, then get a shared handle for it. 513 Create a shared pixmap on the secondary screen using the handle. 514 515 If sync == FALSE -- 516 Set secondary screen to scanout shared linear pixmap. 517 Set the primary screen to do dirty updates to the shared pixmap 518 from the screen pixmap on its own accord. 519 520 If sync == TRUE -- 521 If any of the below steps fail, clean up and fall back to sync == FALSE. 522 Create another shared pixmap on the secondary screen using the handle. 523 Set secondary screen to prepare for scanout and flipping between shared 524 linear pixmaps. 525 Set the primary screen to do dirty updates to the shared pixmaps from the 526 screen pixmap when prompted to by us or the secondary. 527 Prompt the primary to do a dirty update on the first shared pixmap, then 528 defer to the secondary. 529 */ 530 531 if (crtc->scanout_pixmap) 532 RRCrtcDetachScanoutPixmap(crtc); 533 534 if (width == 0 && height == 0) { 535 return TRUE; 536 } 537 538 spix_front = rrCreateSharedPixmap(crtc, primary, 539 width, height, depth, 540 x, y, rotation); 541 if (spix_front == NULL) { 542 ErrorF("randr: failed to create shared pixmap\n"); 543 return FALSE; 544 } 545 546 /* Both source and sink must support required ABI funcs for flipping */ 547 if (sync && 548 pSecondaryScrPriv->rrEnableSharedPixmapFlipping && 549 pSecondaryScrPriv->rrDisableSharedPixmapFlipping && 550 pPrimaryScrPriv->rrStartFlippingPixmapTracking && 551 primary->PresentSharedPixmap && 552 primary->StopFlippingPixmapTracking) { 553 554 PixmapPtr spix_back = rrCreateSharedPixmap(crtc, primary, 555 width, height, depth, 556 x, y, rotation); 557 if (spix_back == NULL) 558 goto fail; 559 560 if (!pSecondaryScrPriv->rrEnableSharedPixmapFlipping(crtc, 561 spix_front, spix_back)) 562 goto fail; 563 564 crtc->scanout_pixmap = spix_front; 565 crtc->scanout_pixmap_back = spix_back; 566 567 if (!pPrimaryScrPriv->rrStartFlippingPixmapTracking(crtc, 568 mrootdraw, 569 spix_front, 570 spix_back, 571 x, y, 0, 0, 572 rotation)) { 573 pSecondaryScrPriv->rrDisableSharedPixmapFlipping(crtc); 574 goto fail; 575 } 576 577 primary->PresentSharedPixmap(spix_front); 578 579 return TRUE; 580 581fail: /* If flipping funcs fail, just fall back to unsynchronized */ 582 if (spix_back) 583 rrDestroySharedPixmap(crtc, spix_back); 584 585 crtc->scanout_pixmap = NULL; 586 crtc->scanout_pixmap_back = NULL; 587 } 588 589 if (sync) { /* Wanted sync, didn't get it */ 590 ErrorF("randr: falling back to unsynchronized pixmap sharing\n"); 591 592 /* Set output property to 0 to indicate to user */ 593 rrSetPixmapSharingSyncProp(0, numOutputs, outputs); 594 } 595 596 if (!pSecondaryScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 597 rrDestroySharedPixmap(crtc, spix_front); 598 ErrorF("randr: failed to set shadow secondary pixmap\n"); 599 return FALSE; 600 } 601 crtc->scanout_pixmap = spix_front; 602 603 primary->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation); 604 605 return TRUE; 606} 607 608static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc) 609{ 610 box->x1 = crtc->x; 611 box->y1 = crtc->y; 612 switch (crtc->rotation) { 613 case RR_Rotate_0: 614 case RR_Rotate_180: 615 default: 616 box->x2 = crtc->x + crtc->mode->mode.width; 617 box->y2 = crtc->y + crtc->mode->mode.height; 618 break; 619 case RR_Rotate_90: 620 case RR_Rotate_270: 621 box->x2 = crtc->x + crtc->mode->mode.height; 622 box->y2 = crtc->y + crtc->mode->mode.width; 623 break; 624 } 625} 626 627static Bool 628rrCheckPixmapBounding(ScreenPtr pScreen, 629 RRCrtcPtr rr_crtc, Rotation rotation, 630 int x, int y, int w, int h) 631{ 632 RegionRec root_pixmap_region, total_region, new_crtc_region; 633 int c; 634 BoxRec newbox; 635 BoxPtr newsize; 636 ScreenPtr secondary; 637 int new_width, new_height; 638 PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen); 639 rrScrPriv(pScreen); 640 641 PixmapRegionInit(&root_pixmap_region, screen_pixmap); 642 RegionInit(&total_region, NULL, 0); 643 644 /* have to iterate all the crtcs of the attached gpu primarys 645 and all their output secondarys */ 646 for (c = 0; c < pScrPriv->numCrtcs; c++) { 647 RRCrtcPtr crtc = pScrPriv->crtcs[c]; 648 649 if (crtc == rr_crtc) { 650 newbox.x1 = x; 651 newbox.y1 = y; 652 if (rotation == RR_Rotate_90 || 653 rotation == RR_Rotate_270) { 654 newbox.x2 = x + h; 655 newbox.y2 = y + w; 656 } else { 657 newbox.x2 = x + w; 658 newbox.y2 = y + h; 659 } 660 } else { 661 if (!crtc->mode) 662 continue; 663 crtc_to_box(&newbox, crtc); 664 } 665 RegionInit(&new_crtc_region, &newbox, 1); 666 RegionUnion(&total_region, &total_region, &new_crtc_region); 667 } 668 669 xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 670 rrScrPrivPtr secondary_priv = rrGetScrPriv(secondary); 671 672 if (!secondary->is_output_secondary) 673 continue; 674 675 for (c = 0; c < secondary_priv->numCrtcs; c++) { 676 RRCrtcPtr secondary_crtc = secondary_priv->crtcs[c]; 677 678 if (secondary_crtc == rr_crtc) { 679 newbox.x1 = x; 680 newbox.y1 = y; 681 if (rotation == RR_Rotate_90 || 682 rotation == RR_Rotate_270) { 683 newbox.x2 = x + h; 684 newbox.y2 = y + w; 685 } else { 686 newbox.x2 = x + w; 687 newbox.y2 = y + h; 688 } 689 } 690 else { 691 if (!secondary_crtc->mode) 692 continue; 693 crtc_to_box(&newbox, secondary_crtc); 694 } 695 RegionInit(&new_crtc_region, &newbox, 1); 696 RegionUnion(&total_region, &total_region, &new_crtc_region); 697 } 698 } 699 700 newsize = RegionExtents(&total_region); 701 new_width = newsize->x2; 702 new_height = newsize->y2; 703 704 if (new_width < screen_pixmap->drawable.width) 705 new_width = screen_pixmap->drawable.width; 706 707 if (new_height < screen_pixmap->drawable.height) 708 new_height = screen_pixmap->drawable.height; 709 710 if (new_width <= screen_pixmap->drawable.width && 711 new_height <= screen_pixmap->drawable.height) { 712 } else { 713 pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0); 714 } 715 716 /* set shatters TODO */ 717 return TRUE; 718} 719 720/* 721 * Request that the Crtc be reconfigured 722 */ 723Bool 724RRCrtcSet(RRCrtcPtr crtc, 725 RRModePtr mode, 726 int x, 727 int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) 728{ 729 ScreenPtr pScreen = crtc->pScreen; 730 Bool ret = FALSE; 731 Bool recompute = TRUE; 732 Bool crtcChanged; 733 int o; 734 735 rrScrPriv(pScreen); 736 737 crtcChanged = FALSE; 738 for (o = 0; o < numOutputs; o++) { 739 if (outputs[o] && outputs[o]->crtc != crtc) { 740 crtcChanged = TRUE; 741 break; 742 } 743 } 744 745 /* See if nothing changed */ 746 if (crtc->mode == mode && 747 crtc->x == x && 748 crtc->y == y && 749 crtc->rotation == rotation && 750 crtc->numOutputs == numOutputs && 751 !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) && 752 !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) && 753 !crtcChanged) { 754 recompute = FALSE; 755 ret = TRUE; 756 } 757 else { 758 if (pScreen->isGPU) { 759 ScreenPtr primary = pScreen->current_primary; 760 int width = 0, height = 0; 761 762 if (mode) { 763 width = mode->mode.width; 764 height = mode->mode.height; 765 } 766 ret = rrCheckPixmapBounding(primary, crtc, 767 rotation, x, y, width, height); 768 if (!ret) 769 return FALSE; 770 771 if (pScreen->current_primary) { 772 Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs); 773 ret = rrSetupPixmapSharing(crtc, width, height, 774 x, y, rotation, sync, 775 numOutputs, outputs); 776 } 777 } 778#if RANDR_12_INTERFACE 779 if (pScrPriv->rrCrtcSet) { 780 ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 781 rotation, numOutputs, outputs); 782 } 783 else 784#endif 785 { 786#if RANDR_10_INTERFACE 787 if (pScrPriv->rrSetConfig) { 788 RRScreenSize size; 789 RRScreenRate rate; 790 791 if (!mode) { 792 RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL); 793 ret = TRUE; 794 } 795 else { 796 size.width = mode->mode.width; 797 size.height = mode->mode.height; 798 if (outputs[0]->mmWidth && outputs[0]->mmHeight) { 799 size.mmWidth = outputs[0]->mmWidth; 800 size.mmHeight = outputs[0]->mmHeight; 801 } 802 else { 803 size.mmWidth = pScreen->mmWidth; 804 size.mmHeight = pScreen->mmHeight; 805 } 806 size.nRates = 1; 807 rate.rate = RRVerticalRefresh(&mode->mode); 808 size.pRates = &rate; 809 ret = 810 (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, 811 &size); 812 /* 813 * Old 1.0 interface tied screen size to mode size 814 */ 815 if (ret) { 816 RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1, 817 outputs); 818 RRScreenSizeNotify(pScreen); 819 } 820 } 821 } 822#endif 823 } 824 if (ret) { 825 826 RRTellChanged(pScreen); 827 828 for (o = 0; o < numOutputs; o++) 829 RRPostPendingProperties(outputs[o]); 830 } 831 } 832 833 if (recompute) 834 RRComputeContiguity(pScreen); 835 836 return ret; 837} 838 839/* 840 * Return crtc transform 841 */ 842RRTransformPtr 843RRCrtcGetTransform(RRCrtcPtr crtc) 844{ 845 RRTransformPtr transform = &crtc->client_pending_transform; 846 847 if (pixman_transform_is_identity(&transform->transform)) 848 return NULL; 849 return transform; 850} 851 852/* 853 * Check whether the pending and current transforms are the same 854 */ 855Bool 856RRCrtcPendingTransform(RRCrtcPtr crtc) 857{ 858 return !RRTransformEqual(&crtc->client_current_transform, 859 &crtc->client_pending_transform); 860} 861 862/* 863 * Destroy a Crtc at shutdown 864 */ 865void 866RRCrtcDestroy(RRCrtcPtr crtc) 867{ 868 FreeResource(crtc->id, 0); 869} 870 871static int 872RRCrtcDestroyResource(void *value, XID pid) 873{ 874 RRCrtcPtr crtc = (RRCrtcPtr) value; 875 ScreenPtr pScreen = crtc->pScreen; 876 877 if (pScreen) { 878 rrScrPriv(pScreen); 879 int i; 880 RRLeasePtr lease, next; 881 882 xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) { 883 int c; 884 for (c = 0; c < lease->numCrtcs; c++) { 885 if (lease->crtcs[c] == crtc) { 886 RRTerminateLease(lease); 887 break; 888 } 889 } 890 } 891 892 for (i = 0; i < pScrPriv->numCrtcs; i++) { 893 if (pScrPriv->crtcs[i] == crtc) { 894 memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 895 (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr)); 896 --pScrPriv->numCrtcs; 897 break; 898 } 899 } 900 901 RRResourcesChanged(pScreen); 902 } 903 904 if (crtc->scanout_pixmap) 905 RRCrtcDetachScanoutPixmap(crtc); 906 free(crtc->gammaRed); 907 if (crtc->mode) 908 RRModeDestroy(crtc->mode); 909 free(crtc->outputs); 910 free(crtc); 911 return 1; 912} 913 914/* 915 * Request that the Crtc gamma be changed 916 */ 917 918Bool 919RRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue) 920{ 921 Bool ret = TRUE; 922 923#if RANDR_12_INTERFACE 924 ScreenPtr pScreen = crtc->pScreen; 925#endif 926 927 memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16)); 928 memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16)); 929 memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16)); 930#if RANDR_12_INTERFACE 931 if (pScreen) { 932 rrScrPriv(pScreen); 933 if (pScrPriv->rrCrtcSetGamma) 934 ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 935 } 936#endif 937 return ret; 938} 939 940/* 941 * Request current gamma back from the DDX (if possible). 942 * This includes gamma size. 943 */ 944Bool 945RRCrtcGammaGet(RRCrtcPtr crtc) 946{ 947 Bool ret = TRUE; 948 949#if RANDR_12_INTERFACE 950 ScreenPtr pScreen = crtc->pScreen; 951#endif 952 953#if RANDR_12_INTERFACE 954 if (pScreen) { 955 rrScrPriv(pScreen); 956 if (pScrPriv->rrCrtcGetGamma) 957 ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 958 } 959#endif 960 return ret; 961} 962 963static Bool RRCrtcInScreen(ScreenPtr pScreen, RRCrtcPtr findCrtc) 964{ 965 rrScrPrivPtr pScrPriv; 966 int c; 967 968 if (pScreen == NULL) 969 return FALSE; 970 971 if (findCrtc == NULL) 972 return FALSE; 973 974 if (!dixPrivateKeyRegistered(rrPrivKey)) 975 return FALSE; 976 977 pScrPriv = rrGetScrPriv(pScreen); 978 for (c = 0; c < pScrPriv->numCrtcs; c++) { 979 if (pScrPriv->crtcs[c] == findCrtc) 980 return TRUE; 981 } 982 983 return FALSE; 984} 985 986Bool RRCrtcExists(ScreenPtr pScreen, RRCrtcPtr findCrtc) 987{ 988 ScreenPtr secondary= NULL; 989 990 if (RRCrtcInScreen(pScreen, findCrtc)) 991 return TRUE; 992 993 xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 994 if (!secondary->is_output_secondary) 995 continue; 996 if (RRCrtcInScreen(secondary, findCrtc)) 997 return TRUE; 998 } 999 1000 return FALSE; 1001} 1002 1003 1004/* 1005 * Notify the extension that the Crtc gamma has been changed 1006 * The driver calls this whenever it has changed the gamma values 1007 * in the RRCrtcRec 1008 */ 1009 1010Bool 1011RRCrtcGammaNotify(RRCrtcPtr crtc) 1012{ 1013 return TRUE; /* not much going on here */ 1014} 1015 1016static void 1017RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 1018 int *width, int *height) 1019{ 1020 BoxRec box; 1021 1022 if (mode == NULL) { 1023 *width = 0; 1024 *height = 0; 1025 return; 1026 } 1027 1028 box.x1 = 0; 1029 box.y1 = 0; 1030 box.x2 = mode->mode.width; 1031 box.y2 = mode->mode.height; 1032 1033 pixman_transform_bounds(transform, &box); 1034 *width = box.x2 - box.x1; 1035 *height = box.y2 - box.y1; 1036} 1037 1038/** 1039 * Returns the width/height that the crtc scans out from the framebuffer 1040 */ 1041void 1042RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 1043{ 1044 RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 1045} 1046 1047/* 1048 * Set the size of the gamma table at server startup time 1049 */ 1050 1051Bool 1052RRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 1053{ 1054 CARD16 *gamma; 1055 1056 if (size == crtc->gammaSize) 1057 return TRUE; 1058 if (size) { 1059 gamma = xallocarray(size, 3 * sizeof(CARD16)); 1060 if (!gamma) 1061 return FALSE; 1062 } 1063 else 1064 gamma = NULL; 1065 free(crtc->gammaRed); 1066 crtc->gammaRed = gamma; 1067 crtc->gammaGreen = gamma + size; 1068 crtc->gammaBlue = gamma + size * 2; 1069 crtc->gammaSize = size; 1070 return TRUE; 1071} 1072 1073/* 1074 * Set the pending CRTC transformation 1075 */ 1076 1077int 1078RRCrtcTransformSet(RRCrtcPtr crtc, 1079 PictTransformPtr transform, 1080 struct pixman_f_transform *f_transform, 1081 struct pixman_f_transform *f_inverse, 1082 char *filter_name, 1083 int filter_len, xFixed * params, int nparams) 1084{ 1085 PictFilterPtr filter = NULL; 1086 int width = 0, height = 0; 1087 1088 if (!crtc->transforms) 1089 return BadValue; 1090 1091 if (filter_len) { 1092 filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 1093 if (!filter) 1094 return BadName; 1095 if (filter->ValidateParams) { 1096 if (!filter->ValidateParams(crtc->pScreen, filter->id, 1097 params, nparams, &width, &height)) 1098 return BadMatch; 1099 } 1100 else { 1101 width = filter->width; 1102 height = filter->height; 1103 } 1104 } 1105 else { 1106 if (nparams) 1107 return BadMatch; 1108 } 1109 if (!RRTransformSetFilter(&crtc->client_pending_transform, 1110 filter, params, nparams, width, height)) 1111 return BadAlloc; 1112 1113 crtc->client_pending_transform.transform = *transform; 1114 crtc->client_pending_transform.f_transform = *f_transform; 1115 crtc->client_pending_transform.f_inverse = *f_inverse; 1116 return Success; 1117} 1118 1119/* 1120 * Initialize crtc type 1121 */ 1122Bool 1123RRCrtcInit(void) 1124{ 1125 RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 1126 if (!RRCrtcType) 1127 return FALSE; 1128 1129 return TRUE; 1130} 1131 1132/* 1133 * Initialize crtc type error value 1134 */ 1135void 1136RRCrtcInitErrorValue(void) 1137{ 1138 SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 1139} 1140 1141int 1142ProcRRGetCrtcInfo(ClientPtr client) 1143{ 1144 REQUEST(xRRGetCrtcInfoReq); 1145 xRRGetCrtcInfoReply rep; 1146 RRCrtcPtr crtc; 1147 CARD8 *extra = NULL; 1148 unsigned long extraLen; 1149 ScreenPtr pScreen; 1150 rrScrPrivPtr pScrPriv; 1151 RRModePtr mode; 1152 RROutput *outputs; 1153 RROutput *possible; 1154 int i, j, k; 1155 int width, height; 1156 BoxRec panned_area; 1157 Bool leased; 1158 1159 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 1160 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1161 1162 leased = RRCrtcIsLeased(crtc); 1163 1164 /* All crtcs must be associated with screens before client 1165 * requests are processed 1166 */ 1167 pScreen = crtc->pScreen; 1168 pScrPriv = rrGetScrPriv(pScreen); 1169 1170 mode = crtc->mode; 1171 1172 rep = (xRRGetCrtcInfoReply) { 1173 .type = X_Reply, 1174 .status = RRSetConfigSuccess, 1175 .sequenceNumber = client->sequence, 1176 .length = 0, 1177 .timestamp = pScrPriv->lastSetTime.milliseconds 1178 }; 1179 if (leased) { 1180 rep.x = rep.y = rep.width = rep.height = 0; 1181 rep.mode = 0; 1182 rep.rotation = RR_Rotate_0; 1183 rep.rotations = RR_Rotate_0; 1184 rep.nOutput = 0; 1185 rep.nPossibleOutput = 0; 1186 rep.length = 0; 1187 extraLen = 0; 1188 } else { 1189 if (pScrPriv->rrGetPanning && 1190 pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 1191 (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 1192 { 1193 rep.x = panned_area.x1; 1194 rep.y = panned_area.y1; 1195 rep.width = panned_area.x2 - panned_area.x1; 1196 rep.height = panned_area.y2 - panned_area.y1; 1197 } 1198 else { 1199 RRCrtcGetScanoutSize(crtc, &width, &height); 1200 rep.x = crtc->x; 1201 rep.y = crtc->y; 1202 rep.width = width; 1203 rep.height = height; 1204 } 1205 rep.mode = mode ? mode->mode.id : 0; 1206 rep.rotation = crtc->rotation; 1207 rep.rotations = crtc->rotations; 1208 rep.nOutput = crtc->numOutputs; 1209 k = 0; 1210 for (i = 0; i < pScrPriv->numOutputs; i++) { 1211 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1212 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1213 if (pScrPriv->outputs[i]->crtcs[j] == crtc) 1214 k++; 1215 } 1216 } 1217 1218 rep.nPossibleOutput = k; 1219 1220 rep.length = rep.nOutput + rep.nPossibleOutput; 1221 1222 extraLen = rep.length << 2; 1223 if (extraLen) { 1224 extra = malloc(extraLen); 1225 if (!extra) 1226 return BadAlloc; 1227 } 1228 1229 outputs = (RROutput *) extra; 1230 possible = (RROutput *) (outputs + rep.nOutput); 1231 1232 for (i = 0; i < crtc->numOutputs; i++) { 1233 outputs[i] = crtc->outputs[i]->id; 1234 if (client->swapped) 1235 swapl(&outputs[i]); 1236 } 1237 k = 0; 1238 for (i = 0; i < pScrPriv->numOutputs; i++) { 1239 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1240 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1241 if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 1242 possible[k] = pScrPriv->outputs[i]->id; 1243 if (client->swapped) 1244 swapl(&possible[k]); 1245 k++; 1246 } 1247 } 1248 } 1249 } 1250 1251 if (client->swapped) { 1252 swaps(&rep.sequenceNumber); 1253 swapl(&rep.length); 1254 swapl(&rep.timestamp); 1255 swaps(&rep.x); 1256 swaps(&rep.y); 1257 swaps(&rep.width); 1258 swaps(&rep.height); 1259 swapl(&rep.mode); 1260 swaps(&rep.rotation); 1261 swaps(&rep.rotations); 1262 swaps(&rep.nOutput); 1263 swaps(&rep.nPossibleOutput); 1264 } 1265 WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 1266 if (extraLen) { 1267 WriteToClient(client, extraLen, extra); 1268 free(extra); 1269 } 1270 1271 return Success; 1272} 1273 1274int 1275ProcRRSetCrtcConfig(ClientPtr client) 1276{ 1277 REQUEST(xRRSetCrtcConfigReq); 1278 xRRSetCrtcConfigReply rep; 1279 ScreenPtr pScreen; 1280 rrScrPrivPtr pScrPriv; 1281 RRCrtcPtr crtc; 1282 RRModePtr mode; 1283 unsigned int numOutputs; 1284 RROutputPtr *outputs = NULL; 1285 RROutput *outputIds; 1286 TimeStamp time; 1287 Rotation rotation; 1288 int ret, i, j; 1289 CARD8 status; 1290 1291 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 1292 numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 1293 1294 VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 1295 1296 if (RRCrtcIsLeased(crtc)) 1297 return BadAccess; 1298 1299 if (stuff->mode == None) { 1300 mode = NULL; 1301 if (numOutputs > 0) 1302 return BadMatch; 1303 } 1304 else { 1305 VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 1306 if (numOutputs == 0) 1307 return BadMatch; 1308 } 1309 if (numOutputs) { 1310 outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 1311 if (!outputs) 1312 return BadAlloc; 1313 } 1314 else 1315 outputs = NULL; 1316 1317 outputIds = (RROutput *) (stuff + 1); 1318 for (i = 0; i < numOutputs; i++) { 1319 ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 1320 RROutputType, client, DixSetAttrAccess); 1321 if (ret != Success) { 1322 free(outputs); 1323 return ret; 1324 } 1325 1326 if (RROutputIsLeased(outputs[i])) { 1327 free(outputs); 1328 return BadAccess; 1329 } 1330 1331 /* validate crtc for this output */ 1332 for (j = 0; j < outputs[i]->numCrtcs; j++) 1333 if (outputs[i]->crtcs[j] == crtc) 1334 break; 1335 if (j == outputs[i]->numCrtcs) { 1336 free(outputs); 1337 return BadMatch; 1338 } 1339 /* validate mode for this output */ 1340 for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 1341 RRModePtr m = (j < outputs[i]->numModes ? 1342 outputs[i]->modes[j] : 1343 outputs[i]->userModes[j - outputs[i]->numModes]); 1344 if (m == mode) 1345 break; 1346 } 1347 if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 1348 free(outputs); 1349 return BadMatch; 1350 } 1351 } 1352 /* validate clones */ 1353 for (i = 0; i < numOutputs; i++) { 1354 for (j = 0; j < numOutputs; j++) { 1355 int k; 1356 1357 if (i == j) 1358 continue; 1359 for (k = 0; k < outputs[i]->numClones; k++) { 1360 if (outputs[i]->clones[k] == outputs[j]) 1361 break; 1362 } 1363 if (k == outputs[i]->numClones) { 1364 free(outputs); 1365 return BadMatch; 1366 } 1367 } 1368 } 1369 1370 pScreen = crtc->pScreen; 1371 pScrPriv = rrGetScrPriv(pScreen); 1372 1373 time = ClientTimeToServerTime(stuff->timestamp); 1374 1375 if (!pScrPriv) { 1376 time = currentTime; 1377 status = RRSetConfigFailed; 1378 goto sendReply; 1379 } 1380 1381 /* 1382 * Validate requested rotation 1383 */ 1384 rotation = (Rotation) stuff->rotation; 1385 1386 /* test the rotation bits only! */ 1387 switch (rotation & 0xf) { 1388 case RR_Rotate_0: 1389 case RR_Rotate_90: 1390 case RR_Rotate_180: 1391 case RR_Rotate_270: 1392 break; 1393 default: 1394 /* 1395 * Invalid rotation 1396 */ 1397 client->errorValue = stuff->rotation; 1398 free(outputs); 1399 return BadValue; 1400 } 1401 1402 if (mode) { 1403 if ((~crtc->rotations) & rotation) { 1404 /* 1405 * requested rotation or reflection not supported by screen 1406 */ 1407 client->errorValue = stuff->rotation; 1408 free(outputs); 1409 return BadMatch; 1410 } 1411 1412#ifdef RANDR_12_INTERFACE 1413 /* 1414 * Check screen size bounds if the DDX provides a 1.2 interface 1415 * for setting screen size. Else, assume the CrtcSet sets 1416 * the size along with the mode. If the driver supports transforms, 1417 * then it must allow crtcs to display a subset of the screen, so 1418 * only do this check for drivers without transform support. 1419 */ 1420 if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 1421 int source_width; 1422 int source_height; 1423 PictTransform transform; 1424 struct pixman_f_transform f_transform, f_inverse; 1425 int width, height; 1426 1427 if (pScreen->isGPU) { 1428 width = pScreen->current_primary->width; 1429 height = pScreen->current_primary->height; 1430 } 1431 else { 1432 width = pScreen->width; 1433 height = pScreen->height; 1434 } 1435 1436 RRTransformCompute(stuff->x, stuff->y, 1437 mode->mode.width, mode->mode.height, 1438 rotation, 1439 &crtc->client_pending_transform, 1440 &transform, &f_transform, &f_inverse); 1441 1442 RRModeGetScanoutSize(mode, &transform, &source_width, 1443 &source_height); 1444 if (stuff->x + source_width > width) { 1445 client->errorValue = stuff->x; 1446 free(outputs); 1447 return BadValue; 1448 } 1449 1450 if (stuff->y + source_height > height) { 1451 client->errorValue = stuff->y; 1452 free(outputs); 1453 return BadValue; 1454 } 1455 } 1456#endif 1457 } 1458 1459 if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 1460 rotation, numOutputs, outputs)) { 1461 status = RRSetConfigFailed; 1462 goto sendReply; 1463 } 1464 status = RRSetConfigSuccess; 1465 pScrPriv->lastSetTime = time; 1466 1467 sendReply: 1468 free(outputs); 1469 1470 rep = (xRRSetCrtcConfigReply) { 1471 .type = X_Reply, 1472 .status = status, 1473 .sequenceNumber = client->sequence, 1474 .length = 0, 1475 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1476 }; 1477 1478 if (client->swapped) { 1479 swaps(&rep.sequenceNumber); 1480 swapl(&rep.length); 1481 swapl(&rep.newTimestamp); 1482 } 1483 WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 1484 1485 return Success; 1486} 1487 1488int 1489ProcRRGetPanning(ClientPtr client) 1490{ 1491 REQUEST(xRRGetPanningReq); 1492 xRRGetPanningReply rep; 1493 RRCrtcPtr crtc; 1494 ScreenPtr pScreen; 1495 rrScrPrivPtr pScrPriv; 1496 BoxRec total; 1497 BoxRec tracking; 1498 INT16 border[4]; 1499 1500 REQUEST_SIZE_MATCH(xRRGetPanningReq); 1501 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1502 1503 /* All crtcs must be associated with screens before client 1504 * requests are processed 1505 */ 1506 pScreen = crtc->pScreen; 1507 pScrPriv = rrGetScrPriv(pScreen); 1508 1509 if (!pScrPriv) 1510 return RRErrorBase + BadRRCrtc; 1511 1512 rep = (xRRGetPanningReply) { 1513 .type = X_Reply, 1514 .status = RRSetConfigSuccess, 1515 .sequenceNumber = client->sequence, 1516 .length = 1, 1517 .timestamp = pScrPriv->lastSetTime.milliseconds 1518 }; 1519 1520 if (pScrPriv->rrGetPanning && 1521 pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 1522 rep.left = total.x1; 1523 rep.top = total.y1; 1524 rep.width = total.x2 - total.x1; 1525 rep.height = total.y2 - total.y1; 1526 rep.track_left = tracking.x1; 1527 rep.track_top = tracking.y1; 1528 rep.track_width = tracking.x2 - tracking.x1; 1529 rep.track_height = tracking.y2 - tracking.y1; 1530 rep.border_left = border[0]; 1531 rep.border_top = border[1]; 1532 rep.border_right = border[2]; 1533 rep.border_bottom = border[3]; 1534 } 1535 1536 if (client->swapped) { 1537 swaps(&rep.sequenceNumber); 1538 swapl(&rep.length); 1539 swapl(&rep.timestamp); 1540 swaps(&rep.left); 1541 swaps(&rep.top); 1542 swaps(&rep.width); 1543 swaps(&rep.height); 1544 swaps(&rep.track_left); 1545 swaps(&rep.track_top); 1546 swaps(&rep.track_width); 1547 swaps(&rep.track_height); 1548 swaps(&rep.border_left); 1549 swaps(&rep.border_top); 1550 swaps(&rep.border_right); 1551 swaps(&rep.border_bottom); 1552 } 1553 WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 1554 return Success; 1555} 1556 1557int 1558ProcRRSetPanning(ClientPtr client) 1559{ 1560 REQUEST(xRRSetPanningReq); 1561 xRRSetPanningReply rep; 1562 RRCrtcPtr crtc; 1563 ScreenPtr pScreen; 1564 rrScrPrivPtr pScrPriv; 1565 TimeStamp time; 1566 BoxRec total; 1567 BoxRec tracking; 1568 INT16 border[4]; 1569 CARD8 status; 1570 1571 REQUEST_SIZE_MATCH(xRRSetPanningReq); 1572 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1573 1574 if (RRCrtcIsLeased(crtc)) 1575 return BadAccess; 1576 1577 /* All crtcs must be associated with screens before client 1578 * requests are processed 1579 */ 1580 pScreen = crtc->pScreen; 1581 pScrPriv = rrGetScrPriv(pScreen); 1582 1583 if (!pScrPriv) { 1584 time = currentTime; 1585 status = RRSetConfigFailed; 1586 goto sendReply; 1587 } 1588 1589 time = ClientTimeToServerTime(stuff->timestamp); 1590 1591 if (!pScrPriv->rrGetPanning) 1592 return RRErrorBase + BadRRCrtc; 1593 1594 total.x1 = stuff->left; 1595 total.y1 = stuff->top; 1596 total.x2 = total.x1 + stuff->width; 1597 total.y2 = total.y1 + stuff->height; 1598 tracking.x1 = stuff->track_left; 1599 tracking.y1 = stuff->track_top; 1600 tracking.x2 = tracking.x1 + stuff->track_width; 1601 tracking.y2 = tracking.y1 + stuff->track_height; 1602 border[0] = stuff->border_left; 1603 border[1] = stuff->border_top; 1604 border[2] = stuff->border_right; 1605 border[3] = stuff->border_bottom; 1606 1607 if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 1608 return BadMatch; 1609 1610 pScrPriv->lastSetTime = time; 1611 1612 status = RRSetConfigSuccess; 1613 1614 sendReply: 1615 rep = (xRRSetPanningReply) { 1616 .type = X_Reply, 1617 .status = status, 1618 .sequenceNumber = client->sequence, 1619 .length = 0, 1620 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1621 }; 1622 1623 if (client->swapped) { 1624 swaps(&rep.sequenceNumber); 1625 swapl(&rep.length); 1626 swapl(&rep.newTimestamp); 1627 } 1628 WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 1629 return Success; 1630} 1631 1632int 1633ProcRRGetCrtcGammaSize(ClientPtr client) 1634{ 1635 REQUEST(xRRGetCrtcGammaSizeReq); 1636 xRRGetCrtcGammaSizeReply reply; 1637 RRCrtcPtr crtc; 1638 1639 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 1640 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1641 1642 /* Gamma retrieval failed, any better error? */ 1643 if (!RRCrtcGammaGet(crtc)) 1644 return RRErrorBase + BadRRCrtc; 1645 1646 reply = (xRRGetCrtcGammaSizeReply) { 1647 .type = X_Reply, 1648 .sequenceNumber = client->sequence, 1649 .length = 0, 1650 .size = crtc->gammaSize 1651 }; 1652 if (client->swapped) { 1653 swaps(&reply.sequenceNumber); 1654 swapl(&reply.length); 1655 swaps(&reply.size); 1656 } 1657 WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 1658 return Success; 1659} 1660 1661int 1662ProcRRGetCrtcGamma(ClientPtr client) 1663{ 1664 REQUEST(xRRGetCrtcGammaReq); 1665 xRRGetCrtcGammaReply reply; 1666 RRCrtcPtr crtc; 1667 unsigned long len; 1668 char *extra = NULL; 1669 1670 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 1671 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1672 1673 /* Gamma retrieval failed, any better error? */ 1674 if (!RRCrtcGammaGet(crtc)) 1675 return RRErrorBase + BadRRCrtc; 1676 1677 len = crtc->gammaSize * 3 * 2; 1678 1679 if (crtc->gammaSize) { 1680 extra = malloc(len); 1681 if (!extra) 1682 return BadAlloc; 1683 } 1684 1685 reply = (xRRGetCrtcGammaReply) { 1686 .type = X_Reply, 1687 .sequenceNumber = client->sequence, 1688 .length = bytes_to_int32(len), 1689 .size = crtc->gammaSize 1690 }; 1691 if (client->swapped) { 1692 swaps(&reply.sequenceNumber); 1693 swapl(&reply.length); 1694 swaps(&reply.size); 1695 } 1696 WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 1697 if (crtc->gammaSize) { 1698 memcpy(extra, crtc->gammaRed, len); 1699 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1700 WriteSwappedDataToClient(client, len, extra); 1701 free(extra); 1702 } 1703 return Success; 1704} 1705 1706int 1707ProcRRSetCrtcGamma(ClientPtr client) 1708{ 1709 REQUEST(xRRSetCrtcGammaReq); 1710 RRCrtcPtr crtc; 1711 unsigned long len; 1712 CARD16 *red, *green, *blue; 1713 1714 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 1715 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1716 1717 if (RRCrtcIsLeased(crtc)) 1718 return BadAccess; 1719 1720 len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 1721 if (len < (stuff->size * 3 + 1) >> 1) 1722 return BadLength; 1723 1724 if (stuff->size != crtc->gammaSize) 1725 return BadMatch; 1726 1727 red = (CARD16 *) (stuff + 1); 1728 green = red + crtc->gammaSize; 1729 blue = green + crtc->gammaSize; 1730 1731 RRCrtcGammaSet(crtc, red, green, blue); 1732 1733 return Success; 1734} 1735 1736/* Version 1.3 additions */ 1737 1738int 1739ProcRRSetCrtcTransform(ClientPtr client) 1740{ 1741 REQUEST(xRRSetCrtcTransformReq); 1742 RRCrtcPtr crtc; 1743 PictTransform transform; 1744 struct pixman_f_transform f_transform, f_inverse; 1745 char *filter; 1746 int nbytes; 1747 xFixed *params; 1748 int nparams; 1749 1750 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 1751 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1752 1753 if (RRCrtcIsLeased(crtc)) 1754 return BadAccess; 1755 1756 PictTransform_from_xRenderTransform(&transform, &stuff->transform); 1757 pixman_f_transform_from_pixman_transform(&f_transform, &transform); 1758 if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 1759 return BadMatch; 1760 1761 filter = (char *) (stuff + 1); 1762 nbytes = stuff->nbytesFilter; 1763 params = (xFixed *) (filter + pad_to_int32(nbytes)); 1764 nparams = ((xFixed *) stuff + client->req_len) - params; 1765 if (nparams < 0) 1766 return BadLength; 1767 1768 return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 1769 filter, nbytes, params, nparams); 1770} 1771 1772#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 1773 1774static int 1775transform_filter_length(RRTransformPtr transform) 1776{ 1777 int nbytes, nparams; 1778 1779 if (transform->filter == NULL) 1780 return 0; 1781 nbytes = strlen(transform->filter->name); 1782 nparams = transform->nparams; 1783 return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 1784} 1785 1786static int 1787transform_filter_encode(ClientPtr client, char *output, 1788 CARD16 *nbytesFilter, 1789 CARD16 *nparamsFilter, RRTransformPtr transform) 1790{ 1791 int nbytes, nparams; 1792 1793 if (transform->filter == NULL) { 1794 *nbytesFilter = 0; 1795 *nparamsFilter = 0; 1796 return 0; 1797 } 1798 nbytes = strlen(transform->filter->name); 1799 nparams = transform->nparams; 1800 *nbytesFilter = nbytes; 1801 *nparamsFilter = nparams; 1802 memcpy(output, transform->filter->name, nbytes); 1803 while ((nbytes & 3) != 0) 1804 output[nbytes++] = 0; 1805 memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 1806 if (client->swapped) { 1807 swaps(nbytesFilter); 1808 swaps(nparamsFilter); 1809 SwapLongs((CARD32 *) (output + nbytes), nparams); 1810 } 1811 nbytes += nparams * sizeof(xFixed); 1812 return nbytes; 1813} 1814 1815static void 1816transform_encode(ClientPtr client, xRenderTransform * wire, 1817 PictTransform * pict) 1818{ 1819 xRenderTransform_from_PictTransform(wire, pict); 1820 if (client->swapped) 1821 SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 1822} 1823 1824int 1825ProcRRGetCrtcTransform(ClientPtr client) 1826{ 1827 REQUEST(xRRGetCrtcTransformReq); 1828 xRRGetCrtcTransformReply *reply; 1829 RRCrtcPtr crtc; 1830 int nextra; 1831 RRTransformPtr current, pending; 1832 char *extra; 1833 1834 REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 1835 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1836 1837 pending = &crtc->client_pending_transform; 1838 current = &crtc->client_current_transform; 1839 1840 nextra = (transform_filter_length(pending) + 1841 transform_filter_length(current)); 1842 1843 reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 1844 if (!reply) 1845 return BadAlloc; 1846 1847 extra = (char *) (reply + 1); 1848 reply->type = X_Reply; 1849 reply->sequenceNumber = client->sequence; 1850 reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 1851 1852 reply->hasTransforms = crtc->transforms; 1853 1854 transform_encode(client, &reply->pendingTransform, &pending->transform); 1855 extra += transform_filter_encode(client, extra, 1856 &reply->pendingNbytesFilter, 1857 &reply->pendingNparamsFilter, pending); 1858 1859 transform_encode(client, &reply->currentTransform, ¤t->transform); 1860 extra += transform_filter_encode(client, extra, 1861 &reply->currentNbytesFilter, 1862 &reply->currentNparamsFilter, current); 1863 1864 if (client->swapped) { 1865 swaps(&reply->sequenceNumber); 1866 swapl(&reply->length); 1867 } 1868 WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 1869 free(reply); 1870 return Success; 1871} 1872 1873static Bool 1874check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 1875{ 1876 rrScrPriv(pScreen); 1877 int i; 1878 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1879 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1880 1881 int left, right, top, bottom; 1882 1883 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1884 continue; 1885 1886 if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 1887 return TRUE; 1888 } 1889 return FALSE; 1890} 1891 1892static Bool 1893constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 1894{ 1895 rrScrPriv(pScreen); 1896 int i; 1897 1898 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1899 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1900 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1901 int nx, ny; 1902 int left, right, top, bottom; 1903 1904 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1905 continue; 1906 1907 miPointerGetPosition(pDev, &nx, &ny); 1908 1909 if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 1910 if (*x < left) 1911 *x = left; 1912 if (*x >= right) 1913 *x = right - 1; 1914 if (*y < top) 1915 *y = top; 1916 if (*y >= bottom) 1917 *y = bottom - 1; 1918 1919 return TRUE; 1920 } 1921 } 1922 return FALSE; 1923} 1924 1925void 1926RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 1927 int *y) 1928{ 1929 rrScrPriv(pScreen); 1930 Bool ret; 1931 ScreenPtr secondary; 1932 1933 /* intentional dead space -> let it float */ 1934 if (pScrPriv->discontiguous) 1935 return; 1936 1937 /* if we're moving inside a crtc, we're fine */ 1938 ret = check_all_screen_crtcs(pScreen, x, y); 1939 if (ret == TRUE) 1940 return; 1941 1942 xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 1943 if (!secondary->is_output_secondary) 1944 continue; 1945 1946 ret = check_all_screen_crtcs(secondary, x, y); 1947 if (ret == TRUE) 1948 return; 1949 } 1950 1951 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1952 ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 1953 if (ret == TRUE) 1954 return; 1955 1956 xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) { 1957 if (!secondary->is_output_secondary) 1958 continue; 1959 1960 ret = constrain_all_screen_crtcs(pDev, secondary, x, y); 1961 if (ret == TRUE) 1962 return; 1963 } 1964} 1965 1966Bool 1967RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 1968{ 1969 rrScrPriv(pDrawable->pScreen); 1970 Bool ret = TRUE; 1971 PixmapPtr *saved_scanout_pixmap; 1972 int i; 1973 1974 saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 1975 if (saved_scanout_pixmap == NULL) 1976 return FALSE; 1977 1978 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1979 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1980 Bool size_fits; 1981 1982 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 1983 1984 if (!crtc->mode && enable) 1985 continue; 1986 if (!crtc->scanout_pixmap && !enable) 1987 continue; 1988 1989 /* not supported with double buffering, needs ABI change for 2 ppix */ 1990 if (crtc->scanout_pixmap_back) { 1991 ret = FALSE; 1992 continue; 1993 } 1994 1995 size_fits = (crtc->mode && 1996 crtc->x == pDrawable->x && 1997 crtc->y == pDrawable->y && 1998 crtc->mode->mode.width == pDrawable->width && 1999 crtc->mode->mode.height == pDrawable->height); 2000 2001 /* is the pixmap already set? */ 2002 if (crtc->scanout_pixmap == pPixmap) { 2003 /* if its a disable then don't care about size */ 2004 if (enable == FALSE) { 2005 /* set scanout to NULL */ 2006 crtc->scanout_pixmap = NULL; 2007 } 2008 else if (!size_fits) { 2009 /* if the size no longer fits then drop off */ 2010 crtc->scanout_pixmap = NULL; 2011 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 2012 2013 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 2014 crtc->rotation, crtc->numOutputs, crtc->outputs); 2015 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 2016 ret = FALSE; 2017 } 2018 else { 2019 /* if the size fits then we are already setup */ 2020 } 2021 } 2022 else { 2023 if (!size_fits) 2024 ret = FALSE; 2025 else if (enable) 2026 crtc->scanout_pixmap = pPixmap; 2027 else 2028 /* reject an attempt to disable someone else's scanout_pixmap */ 2029 ret = FALSE; 2030 } 2031 } 2032 2033 for (i = 0; i < pScrPriv->numCrtcs; i++) { 2034 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 2035 2036 if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 2037 continue; 2038 2039 if (ret) { 2040 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 2041 2042 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 2043 crtc->rotation, crtc->numOutputs, crtc->outputs); 2044 } 2045 else 2046 crtc->scanout_pixmap = saved_scanout_pixmap[i]; 2047 } 2048 free(saved_scanout_pixmap); 2049 2050 return ret; 2051} 2052 2053Bool 2054RRHasScanoutPixmap(ScreenPtr pScreen) 2055{ 2056 rrScrPrivPtr pScrPriv; 2057 int i; 2058 2059 /* Bail out if RandR wasn't initialized. */ 2060 if (!dixPrivateKeyRegistered(rrPrivKey)) 2061 return FALSE; 2062 2063 pScrPriv = rrGetScrPriv(pScreen); 2064 2065 if (!pScreen->is_output_secondary) 2066 return FALSE; 2067 2068 for (i = 0; i < pScrPriv->numCrtcs; i++) { 2069 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 2070 2071 if (crtc->scanout_pixmap) 2072 return TRUE; 2073 } 2074 2075 return FALSE; 2076} 2077