rrcrtc.c revision 25da500f
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; 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 master = crtc->pScreen->current_master; 377 378 if (master && pPixmap->master_pixmap) { 379 /* 380 * Unref the pixmap twice: once for the original reference, and once 381 * for the reference implicitly added by PixmapShareToSlave. 382 */ 383 PixmapUnshareSlavePixmap(pPixmap); 384 385 master->DestroyPixmap(pPixmap->master_pixmap); 386 master->DestroyPixmap(pPixmap->master_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 master = crtc->pScreen->current_master; 399 DrawablePtr mrootdraw = &master->root->drawable; 400 401 if (crtc->scanout_pixmap_back) { 402 pScrPriv->rrDisableSharedPixmapFlipping(crtc); 403 404 if (mrootdraw) { 405 master->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 master->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 master, 431 int width, int height, int depth, 432 int x, int y, Rotation rotation) 433{ 434 PixmapPtr mpix, spix; 435 436 mpix = master->CreatePixmap(master, width, height, depth, 437 CREATE_PIXMAP_USAGE_SHARED); 438 if (!mpix) 439 return NULL; 440 441 spix = PixmapShareToSlave(mpix, crtc->pScreen); 442 if (spix == NULL) { 443 master->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 master = crtc->pScreen->current_master; 506 rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master); 507 rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen); 508 DrawablePtr mrootdraw = &master->root->drawable; 509 int depth = mrootdraw->depth; 510 PixmapPtr spix_front; 511 512 /* Create a pixmap on the master screen, then get a shared handle for it. 513 Create a shared pixmap on the slave screen using the handle. 514 515 If sync == FALSE -- 516 Set slave screen to scanout shared linear pixmap. 517 Set the master 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 slave screen using the handle. 523 Set slave screen to prepare for scanout and flipping between shared 524 linear pixmaps. 525 Set the master screen to do dirty updates to the shared pixmaps from the 526 screen pixmap when prompted to by us or the slave. 527 Prompt the master to do a dirty update on the first shared pixmap, then 528 defer to the slave. 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, master, 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 pSlaveScrPriv->rrEnableSharedPixmapFlipping && 549 pSlaveScrPriv->rrDisableSharedPixmapFlipping && 550 pMasterScrPriv->rrStartFlippingPixmapTracking && 551 master->PresentSharedPixmap && 552 master->StopFlippingPixmapTracking) { 553 554 PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master, 555 width, height, depth, 556 x, y, rotation); 557 if (spix_back == NULL) 558 goto fail; 559 560 if (!pSlaveScrPriv->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 (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc, 568 mrootdraw, 569 spix_front, 570 spix_back, 571 x, y, 0, 0, 572 rotation)) { 573 pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc); 574 goto fail; 575 } 576 577 master->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 (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 597 rrDestroySharedPixmap(crtc, spix_front); 598 ErrorF("randr: failed to set shadow slave pixmap\n"); 599 return FALSE; 600 } 601 crtc->scanout_pixmap = spix_front; 602 603 master->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 slave; 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 masters 645 and all their output slaves */ 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(slave, &pScreen->slave_list, slave_head) { 670 rrScrPrivPtr slave_priv = rrGetScrPriv(slave); 671 672 if (!slave->is_output_slave) 673 continue; 674 675 for (c = 0; c < slave_priv->numCrtcs; c++) { 676 RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; 677 678 if (slave_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 (!slave_crtc->mode) 692 continue; 693 crtc_to_box(&newbox, slave_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 master = pScreen->current_master; 760 int width = 0, height = 0; 761 762 if (mode) { 763 width = mode->mode.width; 764 height = mode->mode.height; 765 } 766 ret = rrCheckPixmapBounding(master, crtc, 767 rotation, x, y, width, height); 768 if (!ret) 769 return FALSE; 770 771 if (pScreen->current_master) { 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 963/* 964 * Notify the extension that the Crtc gamma has been changed 965 * The driver calls this whenever it has changed the gamma values 966 * in the RRCrtcRec 967 */ 968 969Bool 970RRCrtcGammaNotify(RRCrtcPtr crtc) 971{ 972 return TRUE; /* not much going on here */ 973} 974 975static void 976RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 977 int *width, int *height) 978{ 979 BoxRec box; 980 981 if (mode == NULL) { 982 *width = 0; 983 *height = 0; 984 return; 985 } 986 987 box.x1 = 0; 988 box.y1 = 0; 989 box.x2 = mode->mode.width; 990 box.y2 = mode->mode.height; 991 992 pixman_transform_bounds(transform, &box); 993 *width = box.x2 - box.x1; 994 *height = box.y2 - box.y1; 995} 996 997/** 998 * Returns the width/height that the crtc scans out from the framebuffer 999 */ 1000void 1001RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 1002{ 1003 RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 1004} 1005 1006/* 1007 * Set the size of the gamma table at server startup time 1008 */ 1009 1010Bool 1011RRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 1012{ 1013 CARD16 *gamma; 1014 1015 if (size == crtc->gammaSize) 1016 return TRUE; 1017 if (size) { 1018 gamma = xallocarray(size, 3 * sizeof(CARD16)); 1019 if (!gamma) 1020 return FALSE; 1021 } 1022 else 1023 gamma = NULL; 1024 free(crtc->gammaRed); 1025 crtc->gammaRed = gamma; 1026 crtc->gammaGreen = gamma + size; 1027 crtc->gammaBlue = gamma + size * 2; 1028 crtc->gammaSize = size; 1029 return TRUE; 1030} 1031 1032/* 1033 * Set the pending CRTC transformation 1034 */ 1035 1036int 1037RRCrtcTransformSet(RRCrtcPtr crtc, 1038 PictTransformPtr transform, 1039 struct pixman_f_transform *f_transform, 1040 struct pixman_f_transform *f_inverse, 1041 char *filter_name, 1042 int filter_len, xFixed * params, int nparams) 1043{ 1044 PictFilterPtr filter = NULL; 1045 int width = 0, height = 0; 1046 1047 if (!crtc->transforms) 1048 return BadValue; 1049 1050 if (filter_len) { 1051 filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 1052 if (!filter) 1053 return BadName; 1054 if (filter->ValidateParams) { 1055 if (!filter->ValidateParams(crtc->pScreen, filter->id, 1056 params, nparams, &width, &height)) 1057 return BadMatch; 1058 } 1059 else { 1060 width = filter->width; 1061 height = filter->height; 1062 } 1063 } 1064 else { 1065 if (nparams) 1066 return BadMatch; 1067 } 1068 if (!RRTransformSetFilter(&crtc->client_pending_transform, 1069 filter, params, nparams, width, height)) 1070 return BadAlloc; 1071 1072 crtc->client_pending_transform.transform = *transform; 1073 crtc->client_pending_transform.f_transform = *f_transform; 1074 crtc->client_pending_transform.f_inverse = *f_inverse; 1075 return Success; 1076} 1077 1078/* 1079 * Initialize crtc type 1080 */ 1081Bool 1082RRCrtcInit(void) 1083{ 1084 RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 1085 if (!RRCrtcType) 1086 return FALSE; 1087 1088 return TRUE; 1089} 1090 1091/* 1092 * Initialize crtc type error value 1093 */ 1094void 1095RRCrtcInitErrorValue(void) 1096{ 1097 SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 1098} 1099 1100int 1101ProcRRGetCrtcInfo(ClientPtr client) 1102{ 1103 REQUEST(xRRGetCrtcInfoReq); 1104 xRRGetCrtcInfoReply rep; 1105 RRCrtcPtr crtc; 1106 CARD8 *extra = NULL; 1107 unsigned long extraLen; 1108 ScreenPtr pScreen; 1109 rrScrPrivPtr pScrPriv; 1110 RRModePtr mode; 1111 RROutput *outputs; 1112 RROutput *possible; 1113 int i, j, k; 1114 int width, height; 1115 BoxRec panned_area; 1116 Bool leased; 1117 1118 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 1119 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1120 1121 leased = RRCrtcIsLeased(crtc); 1122 1123 /* All crtcs must be associated with screens before client 1124 * requests are processed 1125 */ 1126 pScreen = crtc->pScreen; 1127 pScrPriv = rrGetScrPriv(pScreen); 1128 1129 mode = crtc->mode; 1130 1131 rep = (xRRGetCrtcInfoReply) { 1132 .type = X_Reply, 1133 .status = RRSetConfigSuccess, 1134 .sequenceNumber = client->sequence, 1135 .length = 0, 1136 .timestamp = pScrPriv->lastSetTime.milliseconds 1137 }; 1138 if (leased) { 1139 rep.x = rep.y = rep.width = rep.height = 0; 1140 rep.mode = 0; 1141 rep.rotation = RR_Rotate_0; 1142 rep.rotations = RR_Rotate_0; 1143 rep.nOutput = 0; 1144 rep.nPossibleOutput = 0; 1145 rep.length = 0; 1146 extraLen = 0; 1147 } else { 1148 if (pScrPriv->rrGetPanning && 1149 pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 1150 (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 1151 { 1152 rep.x = panned_area.x1; 1153 rep.y = panned_area.y1; 1154 rep.width = panned_area.x2 - panned_area.x1; 1155 rep.height = panned_area.y2 - panned_area.y1; 1156 } 1157 else { 1158 RRCrtcGetScanoutSize(crtc, &width, &height); 1159 rep.x = crtc->x; 1160 rep.y = crtc->y; 1161 rep.width = width; 1162 rep.height = height; 1163 } 1164 rep.mode = mode ? mode->mode.id : 0; 1165 rep.rotation = crtc->rotation; 1166 rep.rotations = crtc->rotations; 1167 rep.nOutput = crtc->numOutputs; 1168 k = 0; 1169 for (i = 0; i < pScrPriv->numOutputs; i++) { 1170 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1171 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1172 if (pScrPriv->outputs[i]->crtcs[j] == crtc) 1173 k++; 1174 } 1175 } 1176 1177 rep.nPossibleOutput = k; 1178 1179 rep.length = rep.nOutput + rep.nPossibleOutput; 1180 1181 extraLen = rep.length << 2; 1182 if (extraLen) { 1183 extra = malloc(extraLen); 1184 if (!extra) 1185 return BadAlloc; 1186 } 1187 1188 outputs = (RROutput *) extra; 1189 possible = (RROutput *) (outputs + rep.nOutput); 1190 1191 for (i = 0; i < crtc->numOutputs; i++) { 1192 outputs[i] = crtc->outputs[i]->id; 1193 if (client->swapped) 1194 swapl(&outputs[i]); 1195 } 1196 k = 0; 1197 for (i = 0; i < pScrPriv->numOutputs; i++) { 1198 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1199 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1200 if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 1201 possible[k] = pScrPriv->outputs[i]->id; 1202 if (client->swapped) 1203 swapl(&possible[k]); 1204 k++; 1205 } 1206 } 1207 } 1208 } 1209 1210 if (client->swapped) { 1211 swaps(&rep.sequenceNumber); 1212 swapl(&rep.length); 1213 swapl(&rep.timestamp); 1214 swaps(&rep.x); 1215 swaps(&rep.y); 1216 swaps(&rep.width); 1217 swaps(&rep.height); 1218 swapl(&rep.mode); 1219 swaps(&rep.rotation); 1220 swaps(&rep.rotations); 1221 swaps(&rep.nOutput); 1222 swaps(&rep.nPossibleOutput); 1223 } 1224 WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 1225 if (extraLen) { 1226 WriteToClient(client, extraLen, extra); 1227 free(extra); 1228 } 1229 1230 return Success; 1231} 1232 1233int 1234ProcRRSetCrtcConfig(ClientPtr client) 1235{ 1236 REQUEST(xRRSetCrtcConfigReq); 1237 xRRSetCrtcConfigReply rep; 1238 ScreenPtr pScreen; 1239 rrScrPrivPtr pScrPriv; 1240 RRCrtcPtr crtc; 1241 RRModePtr mode; 1242 int numOutputs; 1243 RROutputPtr *outputs = NULL; 1244 RROutput *outputIds; 1245 TimeStamp time; 1246 Rotation rotation; 1247 int ret, i, j; 1248 CARD8 status; 1249 1250 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 1251 numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 1252 1253 VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 1254 1255 if (RRCrtcIsLeased(crtc)) 1256 return BadAccess; 1257 1258 if (stuff->mode == None) { 1259 mode = NULL; 1260 if (numOutputs > 0) 1261 return BadMatch; 1262 } 1263 else { 1264 VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 1265 if (numOutputs == 0) 1266 return BadMatch; 1267 } 1268 if (numOutputs) { 1269 outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 1270 if (!outputs) 1271 return BadAlloc; 1272 } 1273 else 1274 outputs = NULL; 1275 1276 outputIds = (RROutput *) (stuff + 1); 1277 for (i = 0; i < numOutputs; i++) { 1278 ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 1279 RROutputType, client, DixSetAttrAccess); 1280 if (ret != Success) { 1281 free(outputs); 1282 return ret; 1283 } 1284 1285 if (RROutputIsLeased(outputs[i])) { 1286 free(outputs); 1287 return BadAccess; 1288 } 1289 1290 /* validate crtc for this output */ 1291 for (j = 0; j < outputs[i]->numCrtcs; j++) 1292 if (outputs[i]->crtcs[j] == crtc) 1293 break; 1294 if (j == outputs[i]->numCrtcs) { 1295 free(outputs); 1296 return BadMatch; 1297 } 1298 /* validate mode for this output */ 1299 for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 1300 RRModePtr m = (j < outputs[i]->numModes ? 1301 outputs[i]->modes[j] : 1302 outputs[i]->userModes[j - outputs[i]->numModes]); 1303 if (m == mode) 1304 break; 1305 } 1306 if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 1307 free(outputs); 1308 return BadMatch; 1309 } 1310 } 1311 /* validate clones */ 1312 for (i = 0; i < numOutputs; i++) { 1313 for (j = 0; j < numOutputs; j++) { 1314 int k; 1315 1316 if (i == j) 1317 continue; 1318 for (k = 0; k < outputs[i]->numClones; k++) { 1319 if (outputs[i]->clones[k] == outputs[j]) 1320 break; 1321 } 1322 if (k == outputs[i]->numClones) { 1323 free(outputs); 1324 return BadMatch; 1325 } 1326 } 1327 } 1328 1329 pScreen = crtc->pScreen; 1330 pScrPriv = rrGetScrPriv(pScreen); 1331 1332 time = ClientTimeToServerTime(stuff->timestamp); 1333 1334 if (!pScrPriv) { 1335 time = currentTime; 1336 status = RRSetConfigFailed; 1337 goto sendReply; 1338 } 1339 1340 /* 1341 * Validate requested rotation 1342 */ 1343 rotation = (Rotation) stuff->rotation; 1344 1345 /* test the rotation bits only! */ 1346 switch (rotation & 0xf) { 1347 case RR_Rotate_0: 1348 case RR_Rotate_90: 1349 case RR_Rotate_180: 1350 case RR_Rotate_270: 1351 break; 1352 default: 1353 /* 1354 * Invalid rotation 1355 */ 1356 client->errorValue = stuff->rotation; 1357 free(outputs); 1358 return BadValue; 1359 } 1360 1361 if (mode) { 1362 if ((~crtc->rotations) & rotation) { 1363 /* 1364 * requested rotation or reflection not supported by screen 1365 */ 1366 client->errorValue = stuff->rotation; 1367 free(outputs); 1368 return BadMatch; 1369 } 1370 1371#ifdef RANDR_12_INTERFACE 1372 /* 1373 * Check screen size bounds if the DDX provides a 1.2 interface 1374 * for setting screen size. Else, assume the CrtcSet sets 1375 * the size along with the mode. If the driver supports transforms, 1376 * then it must allow crtcs to display a subset of the screen, so 1377 * only do this check for drivers without transform support. 1378 */ 1379 if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 1380 int source_width; 1381 int source_height; 1382 PictTransform transform; 1383 struct pixman_f_transform f_transform, f_inverse; 1384 int width, height; 1385 1386 if (pScreen->isGPU) { 1387 width = pScreen->current_master->width; 1388 height = pScreen->current_master->height; 1389 } 1390 else { 1391 width = pScreen->width; 1392 height = pScreen->height; 1393 } 1394 1395 RRTransformCompute(stuff->x, stuff->y, 1396 mode->mode.width, mode->mode.height, 1397 rotation, 1398 &crtc->client_pending_transform, 1399 &transform, &f_transform, &f_inverse); 1400 1401 RRModeGetScanoutSize(mode, &transform, &source_width, 1402 &source_height); 1403 if (stuff->x + source_width > width) { 1404 client->errorValue = stuff->x; 1405 free(outputs); 1406 return BadValue; 1407 } 1408 1409 if (stuff->y + source_height > height) { 1410 client->errorValue = stuff->y; 1411 free(outputs); 1412 return BadValue; 1413 } 1414 } 1415#endif 1416 } 1417 1418 if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 1419 rotation, numOutputs, outputs)) { 1420 status = RRSetConfigFailed; 1421 goto sendReply; 1422 } 1423 status = RRSetConfigSuccess; 1424 pScrPriv->lastSetTime = time; 1425 1426 sendReply: 1427 free(outputs); 1428 1429 rep = (xRRSetCrtcConfigReply) { 1430 .type = X_Reply, 1431 .status = status, 1432 .sequenceNumber = client->sequence, 1433 .length = 0, 1434 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1435 }; 1436 1437 if (client->swapped) { 1438 swaps(&rep.sequenceNumber); 1439 swapl(&rep.length); 1440 swapl(&rep.newTimestamp); 1441 } 1442 WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 1443 1444 return Success; 1445} 1446 1447int 1448ProcRRGetPanning(ClientPtr client) 1449{ 1450 REQUEST(xRRGetPanningReq); 1451 xRRGetPanningReply rep; 1452 RRCrtcPtr crtc; 1453 ScreenPtr pScreen; 1454 rrScrPrivPtr pScrPriv; 1455 BoxRec total; 1456 BoxRec tracking; 1457 INT16 border[4]; 1458 1459 REQUEST_SIZE_MATCH(xRRGetPanningReq); 1460 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1461 1462 /* All crtcs must be associated with screens before client 1463 * requests are processed 1464 */ 1465 pScreen = crtc->pScreen; 1466 pScrPriv = rrGetScrPriv(pScreen); 1467 1468 if (!pScrPriv) 1469 return RRErrorBase + BadRRCrtc; 1470 1471 rep = (xRRGetPanningReply) { 1472 .type = X_Reply, 1473 .status = RRSetConfigSuccess, 1474 .sequenceNumber = client->sequence, 1475 .length = 1, 1476 .timestamp = pScrPriv->lastSetTime.milliseconds 1477 }; 1478 1479 if (pScrPriv->rrGetPanning && 1480 pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 1481 rep.left = total.x1; 1482 rep.top = total.y1; 1483 rep.width = total.x2 - total.x1; 1484 rep.height = total.y2 - total.y1; 1485 rep.track_left = tracking.x1; 1486 rep.track_top = tracking.y1; 1487 rep.track_width = tracking.x2 - tracking.x1; 1488 rep.track_height = tracking.y2 - tracking.y1; 1489 rep.border_left = border[0]; 1490 rep.border_top = border[1]; 1491 rep.border_right = border[2]; 1492 rep.border_bottom = border[3]; 1493 } 1494 1495 if (client->swapped) { 1496 swaps(&rep.sequenceNumber); 1497 swapl(&rep.length); 1498 swapl(&rep.timestamp); 1499 swaps(&rep.left); 1500 swaps(&rep.top); 1501 swaps(&rep.width); 1502 swaps(&rep.height); 1503 swaps(&rep.track_left); 1504 swaps(&rep.track_top); 1505 swaps(&rep.track_width); 1506 swaps(&rep.track_height); 1507 swaps(&rep.border_left); 1508 swaps(&rep.border_top); 1509 swaps(&rep.border_right); 1510 swaps(&rep.border_bottom); 1511 } 1512 WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 1513 return Success; 1514} 1515 1516int 1517ProcRRSetPanning(ClientPtr client) 1518{ 1519 REQUEST(xRRSetPanningReq); 1520 xRRSetPanningReply rep; 1521 RRCrtcPtr crtc; 1522 ScreenPtr pScreen; 1523 rrScrPrivPtr pScrPriv; 1524 TimeStamp time; 1525 BoxRec total; 1526 BoxRec tracking; 1527 INT16 border[4]; 1528 CARD8 status; 1529 1530 REQUEST_SIZE_MATCH(xRRSetPanningReq); 1531 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1532 1533 if (RRCrtcIsLeased(crtc)) 1534 return BadAccess; 1535 1536 /* All crtcs must be associated with screens before client 1537 * requests are processed 1538 */ 1539 pScreen = crtc->pScreen; 1540 pScrPriv = rrGetScrPriv(pScreen); 1541 1542 if (!pScrPriv) { 1543 time = currentTime; 1544 status = RRSetConfigFailed; 1545 goto sendReply; 1546 } 1547 1548 time = ClientTimeToServerTime(stuff->timestamp); 1549 1550 if (!pScrPriv->rrGetPanning) 1551 return RRErrorBase + BadRRCrtc; 1552 1553 total.x1 = stuff->left; 1554 total.y1 = stuff->top; 1555 total.x2 = total.x1 + stuff->width; 1556 total.y2 = total.y1 + stuff->height; 1557 tracking.x1 = stuff->track_left; 1558 tracking.y1 = stuff->track_top; 1559 tracking.x2 = tracking.x1 + stuff->track_width; 1560 tracking.y2 = tracking.y1 + stuff->track_height; 1561 border[0] = stuff->border_left; 1562 border[1] = stuff->border_top; 1563 border[2] = stuff->border_right; 1564 border[3] = stuff->border_bottom; 1565 1566 if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 1567 return BadMatch; 1568 1569 pScrPriv->lastSetTime = time; 1570 1571 status = RRSetConfigSuccess; 1572 1573 sendReply: 1574 rep = (xRRSetPanningReply) { 1575 .type = X_Reply, 1576 .status = status, 1577 .sequenceNumber = client->sequence, 1578 .length = 0, 1579 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1580 }; 1581 1582 if (client->swapped) { 1583 swaps(&rep.sequenceNumber); 1584 swapl(&rep.length); 1585 swapl(&rep.newTimestamp); 1586 } 1587 WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 1588 return Success; 1589} 1590 1591int 1592ProcRRGetCrtcGammaSize(ClientPtr client) 1593{ 1594 REQUEST(xRRGetCrtcGammaSizeReq); 1595 xRRGetCrtcGammaSizeReply reply; 1596 RRCrtcPtr crtc; 1597 1598 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 1599 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1600 1601 /* Gamma retrieval failed, any better error? */ 1602 if (!RRCrtcGammaGet(crtc)) 1603 return RRErrorBase + BadRRCrtc; 1604 1605 reply = (xRRGetCrtcGammaSizeReply) { 1606 .type = X_Reply, 1607 .sequenceNumber = client->sequence, 1608 .length = 0, 1609 .size = crtc->gammaSize 1610 }; 1611 if (client->swapped) { 1612 swaps(&reply.sequenceNumber); 1613 swapl(&reply.length); 1614 swaps(&reply.size); 1615 } 1616 WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 1617 return Success; 1618} 1619 1620int 1621ProcRRGetCrtcGamma(ClientPtr client) 1622{ 1623 REQUEST(xRRGetCrtcGammaReq); 1624 xRRGetCrtcGammaReply reply; 1625 RRCrtcPtr crtc; 1626 unsigned long len; 1627 char *extra = NULL; 1628 1629 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 1630 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1631 1632 /* Gamma retrieval failed, any better error? */ 1633 if (!RRCrtcGammaGet(crtc)) 1634 return RRErrorBase + BadRRCrtc; 1635 1636 len = crtc->gammaSize * 3 * 2; 1637 1638 if (crtc->gammaSize) { 1639 extra = malloc(len); 1640 if (!extra) 1641 return BadAlloc; 1642 } 1643 1644 reply = (xRRGetCrtcGammaReply) { 1645 .type = X_Reply, 1646 .sequenceNumber = client->sequence, 1647 .length = bytes_to_int32(len), 1648 .size = crtc->gammaSize 1649 }; 1650 if (client->swapped) { 1651 swaps(&reply.sequenceNumber); 1652 swapl(&reply.length); 1653 swaps(&reply.size); 1654 } 1655 WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 1656 if (crtc->gammaSize) { 1657 memcpy(extra, crtc->gammaRed, len); 1658 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1659 WriteSwappedDataToClient(client, len, extra); 1660 free(extra); 1661 } 1662 return Success; 1663} 1664 1665int 1666ProcRRSetCrtcGamma(ClientPtr client) 1667{ 1668 REQUEST(xRRSetCrtcGammaReq); 1669 RRCrtcPtr crtc; 1670 unsigned long len; 1671 CARD16 *red, *green, *blue; 1672 1673 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 1674 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1675 1676 if (RRCrtcIsLeased(crtc)) 1677 return BadAccess; 1678 1679 len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 1680 if (len < (stuff->size * 3 + 1) >> 1) 1681 return BadLength; 1682 1683 if (stuff->size != crtc->gammaSize) 1684 return BadMatch; 1685 1686 red = (CARD16 *) (stuff + 1); 1687 green = red + crtc->gammaSize; 1688 blue = green + crtc->gammaSize; 1689 1690 RRCrtcGammaSet(crtc, red, green, blue); 1691 1692 return Success; 1693} 1694 1695/* Version 1.3 additions */ 1696 1697int 1698ProcRRSetCrtcTransform(ClientPtr client) 1699{ 1700 REQUEST(xRRSetCrtcTransformReq); 1701 RRCrtcPtr crtc; 1702 PictTransform transform; 1703 struct pixman_f_transform f_transform, f_inverse; 1704 char *filter; 1705 int nbytes; 1706 xFixed *params; 1707 int nparams; 1708 1709 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 1710 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1711 1712 if (RRCrtcIsLeased(crtc)) 1713 return BadAccess; 1714 1715 PictTransform_from_xRenderTransform(&transform, &stuff->transform); 1716 pixman_f_transform_from_pixman_transform(&f_transform, &transform); 1717 if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 1718 return BadMatch; 1719 1720 filter = (char *) (stuff + 1); 1721 nbytes = stuff->nbytesFilter; 1722 params = (xFixed *) (filter + pad_to_int32(nbytes)); 1723 nparams = ((xFixed *) stuff + client->req_len) - params; 1724 if (nparams < 0) 1725 return BadLength; 1726 1727 return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 1728 filter, nbytes, params, nparams); 1729} 1730 1731#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 1732 1733static int 1734transform_filter_length(RRTransformPtr transform) 1735{ 1736 int nbytes, nparams; 1737 1738 if (transform->filter == NULL) 1739 return 0; 1740 nbytes = strlen(transform->filter->name); 1741 nparams = transform->nparams; 1742 return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 1743} 1744 1745static int 1746transform_filter_encode(ClientPtr client, char *output, 1747 CARD16 *nbytesFilter, 1748 CARD16 *nparamsFilter, RRTransformPtr transform) 1749{ 1750 int nbytes, nparams; 1751 1752 if (transform->filter == NULL) { 1753 *nbytesFilter = 0; 1754 *nparamsFilter = 0; 1755 return 0; 1756 } 1757 nbytes = strlen(transform->filter->name); 1758 nparams = transform->nparams; 1759 *nbytesFilter = nbytes; 1760 *nparamsFilter = nparams; 1761 memcpy(output, transform->filter->name, nbytes); 1762 while ((nbytes & 3) != 0) 1763 output[nbytes++] = 0; 1764 memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 1765 if (client->swapped) { 1766 swaps(nbytesFilter); 1767 swaps(nparamsFilter); 1768 SwapLongs((CARD32 *) (output + nbytes), nparams); 1769 } 1770 nbytes += nparams * sizeof(xFixed); 1771 return nbytes; 1772} 1773 1774static void 1775transform_encode(ClientPtr client, xRenderTransform * wire, 1776 PictTransform * pict) 1777{ 1778 xRenderTransform_from_PictTransform(wire, pict); 1779 if (client->swapped) 1780 SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 1781} 1782 1783int 1784ProcRRGetCrtcTransform(ClientPtr client) 1785{ 1786 REQUEST(xRRGetCrtcTransformReq); 1787 xRRGetCrtcTransformReply *reply; 1788 RRCrtcPtr crtc; 1789 int nextra; 1790 RRTransformPtr current, pending; 1791 char *extra; 1792 1793 REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 1794 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1795 1796 pending = &crtc->client_pending_transform; 1797 current = &crtc->client_current_transform; 1798 1799 nextra = (transform_filter_length(pending) + 1800 transform_filter_length(current)); 1801 1802 reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 1803 if (!reply) 1804 return BadAlloc; 1805 1806 extra = (char *) (reply + 1); 1807 reply->type = X_Reply; 1808 reply->sequenceNumber = client->sequence; 1809 reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 1810 1811 reply->hasTransforms = crtc->transforms; 1812 1813 transform_encode(client, &reply->pendingTransform, &pending->transform); 1814 extra += transform_filter_encode(client, extra, 1815 &reply->pendingNbytesFilter, 1816 &reply->pendingNparamsFilter, pending); 1817 1818 transform_encode(client, &reply->currentTransform, ¤t->transform); 1819 extra += transform_filter_encode(client, extra, 1820 &reply->currentNbytesFilter, 1821 &reply->currentNparamsFilter, current); 1822 1823 if (client->swapped) { 1824 swaps(&reply->sequenceNumber); 1825 swapl(&reply->length); 1826 } 1827 WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 1828 free(reply); 1829 return Success; 1830} 1831 1832static Bool 1833check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 1834{ 1835 rrScrPriv(pScreen); 1836 int i; 1837 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1838 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1839 1840 int left, right, top, bottom; 1841 1842 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1843 continue; 1844 1845 if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 1846 return TRUE; 1847 } 1848 return FALSE; 1849} 1850 1851static Bool 1852constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 1853{ 1854 rrScrPriv(pScreen); 1855 int i; 1856 1857 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1858 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1859 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1860 int nx, ny; 1861 int left, right, top, bottom; 1862 1863 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1864 continue; 1865 1866 miPointerGetPosition(pDev, &nx, &ny); 1867 1868 if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 1869 if (*x < left) 1870 *x = left; 1871 if (*x >= right) 1872 *x = right - 1; 1873 if (*y < top) 1874 *y = top; 1875 if (*y >= bottom) 1876 *y = bottom - 1; 1877 1878 return TRUE; 1879 } 1880 } 1881 return FALSE; 1882} 1883 1884void 1885RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 1886 int *y) 1887{ 1888 rrScrPriv(pScreen); 1889 Bool ret; 1890 ScreenPtr slave; 1891 1892 /* intentional dead space -> let it float */ 1893 if (pScrPriv->discontiguous) 1894 return; 1895 1896 /* if we're moving inside a crtc, we're fine */ 1897 ret = check_all_screen_crtcs(pScreen, x, y); 1898 if (ret == TRUE) 1899 return; 1900 1901 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 1902 if (!slave->is_output_slave) 1903 continue; 1904 1905 ret = check_all_screen_crtcs(slave, x, y); 1906 if (ret == TRUE) 1907 return; 1908 } 1909 1910 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1911 ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 1912 if (ret == TRUE) 1913 return; 1914 1915 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 1916 if (!slave->is_output_slave) 1917 continue; 1918 1919 ret = constrain_all_screen_crtcs(pDev, slave, x, y); 1920 if (ret == TRUE) 1921 return; 1922 } 1923} 1924 1925Bool 1926RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 1927{ 1928 rrScrPriv(pDrawable->pScreen); 1929 Bool ret = TRUE; 1930 PixmapPtr *saved_scanout_pixmap; 1931 int i; 1932 1933 saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 1934 if (saved_scanout_pixmap == NULL) 1935 return FALSE; 1936 1937 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1938 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1939 Bool size_fits; 1940 1941 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 1942 1943 if (!crtc->mode && enable) 1944 continue; 1945 if (!crtc->scanout_pixmap && !enable) 1946 continue; 1947 1948 /* not supported with double buffering, needs ABI change for 2 ppix */ 1949 if (crtc->scanout_pixmap_back) { 1950 ret = FALSE; 1951 continue; 1952 } 1953 1954 size_fits = (crtc->mode && 1955 crtc->x == pDrawable->x && 1956 crtc->y == pDrawable->y && 1957 crtc->mode->mode.width == pDrawable->width && 1958 crtc->mode->mode.height == pDrawable->height); 1959 1960 /* is the pixmap already set? */ 1961 if (crtc->scanout_pixmap == pPixmap) { 1962 /* if its a disable then don't care about size */ 1963 if (enable == FALSE) { 1964 /* set scanout to NULL */ 1965 crtc->scanout_pixmap = NULL; 1966 } 1967 else if (!size_fits) { 1968 /* if the size no longer fits then drop off */ 1969 crtc->scanout_pixmap = NULL; 1970 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 1971 1972 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 1973 crtc->rotation, crtc->numOutputs, crtc->outputs); 1974 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 1975 ret = FALSE; 1976 } 1977 else { 1978 /* if the size fits then we are already setup */ 1979 } 1980 } 1981 else { 1982 if (!size_fits) 1983 ret = FALSE; 1984 else if (enable) 1985 crtc->scanout_pixmap = pPixmap; 1986 else 1987 /* reject an attempt to disable someone else's scanout_pixmap */ 1988 ret = FALSE; 1989 } 1990 } 1991 1992 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1993 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1994 1995 if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 1996 continue; 1997 1998 if (ret) { 1999 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 2000 2001 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 2002 crtc->rotation, crtc->numOutputs, crtc->outputs); 2003 } 2004 else 2005 crtc->scanout_pixmap = saved_scanout_pixmap[i]; 2006 } 2007 free(saved_scanout_pixmap); 2008 2009 return ret; 2010} 2011 2012Bool 2013RRHasScanoutPixmap(ScreenPtr pScreen) 2014{ 2015 rrScrPriv(pScreen); 2016 int i; 2017 2018 if (!pScreen->is_output_slave) 2019 return FALSE; 2020 2021 for (i = 0; i < pScrPriv->numCrtcs; i++) { 2022 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 2023 2024 if (crtc->scanout_pixmap) 2025 return TRUE; 2026 } 2027 2028 return FALSE; 2029} 2030