rrcrtc.c revision 1b5d61b8
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 master->StopFlippingPixmapTracking(mrootdraw, 405 crtc->scanout_pixmap, 406 crtc->scanout_pixmap_back); 407 408 rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back); 409 crtc->scanout_pixmap_back = NULL; 410 } 411 else { 412 pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL); 413 master->StopPixmapTracking(mrootdraw, 414 crtc->scanout_pixmap); 415 } 416 417 rrDestroySharedPixmap(crtc, crtc->scanout_pixmap); 418 crtc->scanout_pixmap = NULL; 419 } 420 421 RRCrtcChanged(crtc, TRUE); 422} 423 424static PixmapPtr 425rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master, 426 int width, int height, int depth, 427 int x, int y, Rotation rotation) 428{ 429 PixmapPtr mpix, spix; 430 431 mpix = master->CreatePixmap(master, width, height, depth, 432 CREATE_PIXMAP_USAGE_SHARED); 433 if (!mpix) 434 return NULL; 435 436 spix = PixmapShareToSlave(mpix, crtc->pScreen); 437 if (spix == NULL) { 438 master->DestroyPixmap(mpix); 439 return NULL; 440 } 441 442 return spix; 443} 444 445static Bool 446rrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs) 447{ 448 /* Determine if the user wants prime syncing */ 449 int o; 450 const char *syncStr = PRIME_SYNC_PROP; 451 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 452 if (syncProp == None) 453 return TRUE; 454 455 /* If one output doesn't want sync, no sync */ 456 for (o = 0; o < numOutputs; o++) { 457 RRPropertyValuePtr val; 458 459 /* Try pending value first, then current value */ 460 if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) && 461 val->data) { 462 if (!(*(char *) val->data)) 463 return FALSE; 464 continue; 465 } 466 467 if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) && 468 val->data) { 469 if (!(*(char *) val->data)) 470 return FALSE; 471 continue; 472 } 473 } 474 475 return TRUE; 476} 477 478static void 479rrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs) 480{ 481 int o; 482 const char *syncStr = PRIME_SYNC_PROP; 483 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 484 if (syncProp == None) 485 return; 486 487 for (o = 0; o < numOutputs; o++) { 488 RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp); 489 if (prop) 490 RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER, 491 8, PropModeReplace, 1, &val, FALSE, TRUE); 492 } 493} 494 495static Bool 496rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height, 497 int x, int y, Rotation rotation, Bool sync, 498 int numOutputs, RROutputPtr * outputs) 499{ 500 ScreenPtr master = crtc->pScreen->current_master; 501 rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master); 502 rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen); 503 DrawablePtr mrootdraw = &master->root->drawable; 504 int depth = mrootdraw->depth; 505 PixmapPtr spix_front; 506 507 /* Create a pixmap on the master screen, then get a shared handle for it. 508 Create a shared pixmap on the slave screen using the handle. 509 510 If sync == FALSE -- 511 Set slave screen to scanout shared linear pixmap. 512 Set the master screen to do dirty updates to the shared pixmap 513 from the screen pixmap on its own accord. 514 515 If sync == TRUE -- 516 If any of the below steps fail, clean up and fall back to sync == FALSE. 517 Create another shared pixmap on the slave screen using the handle. 518 Set slave screen to prepare for scanout and flipping between shared 519 linear pixmaps. 520 Set the master screen to do dirty updates to the shared pixmaps from the 521 screen pixmap when prompted to by us or the slave. 522 Prompt the master to do a dirty update on the first shared pixmap, then 523 defer to the slave. 524 */ 525 526 if (crtc->scanout_pixmap) 527 RRCrtcDetachScanoutPixmap(crtc); 528 529 if (width == 0 && height == 0) { 530 return TRUE; 531 } 532 533 spix_front = rrCreateSharedPixmap(crtc, master, 534 width, height, depth, 535 x, y, rotation); 536 if (spix_front == NULL) { 537 ErrorF("randr: failed to create shared pixmap\n"); 538 return FALSE; 539 } 540 541 /* Both source and sink must support required ABI funcs for flipping */ 542 if (sync && 543 pSlaveScrPriv->rrEnableSharedPixmapFlipping && 544 pSlaveScrPriv->rrDisableSharedPixmapFlipping && 545 pMasterScrPriv->rrStartFlippingPixmapTracking && 546 master->PresentSharedPixmap && 547 master->StopFlippingPixmapTracking) { 548 549 PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master, 550 width, height, depth, 551 x, y, rotation); 552 if (spix_back == NULL) 553 goto fail; 554 555 if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc, 556 spix_front, spix_back)) 557 goto fail; 558 559 crtc->scanout_pixmap = spix_front; 560 crtc->scanout_pixmap_back = spix_back; 561 562 if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc, 563 mrootdraw, 564 spix_front, 565 spix_back, 566 x, y, 0, 0, 567 rotation)) { 568 pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc); 569 goto fail; 570 } 571 572 master->PresentSharedPixmap(spix_front); 573 574 return TRUE; 575 576fail: /* If flipping funcs fail, just fall back to unsynchronized */ 577 if (spix_back) 578 rrDestroySharedPixmap(crtc, spix_back); 579 580 crtc->scanout_pixmap = NULL; 581 crtc->scanout_pixmap_back = NULL; 582 } 583 584 if (sync) { /* Wanted sync, didn't get it */ 585 ErrorF("randr: falling back to unsynchronized pixmap sharing\n"); 586 587 /* Set output property to 0 to indicate to user */ 588 rrSetPixmapSharingSyncProp(0, numOutputs, outputs); 589 } 590 591 if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) { 592 rrDestroySharedPixmap(crtc, spix_front); 593 ErrorF("randr: failed to set shadow slave pixmap\n"); 594 return FALSE; 595 } 596 crtc->scanout_pixmap = spix_front; 597 598 master->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation); 599 600 return TRUE; 601} 602 603static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc) 604{ 605 box->x1 = crtc->x; 606 box->y1 = crtc->y; 607 switch (crtc->rotation) { 608 case RR_Rotate_0: 609 case RR_Rotate_180: 610 default: 611 box->x2 = crtc->x + crtc->mode->mode.width; 612 box->y2 = crtc->y + crtc->mode->mode.height; 613 break; 614 case RR_Rotate_90: 615 case RR_Rotate_270: 616 box->x2 = crtc->x + crtc->mode->mode.height; 617 box->y2 = crtc->y + crtc->mode->mode.width; 618 break; 619 } 620} 621 622static Bool 623rrCheckPixmapBounding(ScreenPtr pScreen, 624 RRCrtcPtr rr_crtc, Rotation rotation, 625 int x, int y, int w, int h) 626{ 627 RegionRec root_pixmap_region, total_region, new_crtc_region; 628 int c; 629 BoxRec newbox; 630 BoxPtr newsize; 631 ScreenPtr slave; 632 int new_width, new_height; 633 PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen); 634 rrScrPriv(pScreen); 635 636 PixmapRegionInit(&root_pixmap_region, screen_pixmap); 637 RegionInit(&total_region, NULL, 0); 638 639 /* have to iterate all the crtcs of the attached gpu masters 640 and all their output slaves */ 641 for (c = 0; c < pScrPriv->numCrtcs; c++) { 642 RRCrtcPtr crtc = pScrPriv->crtcs[c]; 643 644 if (crtc == rr_crtc) { 645 newbox.x1 = x; 646 newbox.y1 = y; 647 if (rotation == RR_Rotate_90 || 648 rotation == RR_Rotate_270) { 649 newbox.x2 = x + h; 650 newbox.y2 = y + w; 651 } else { 652 newbox.x2 = x + w; 653 newbox.y2 = y + h; 654 } 655 } else { 656 if (!crtc->mode) 657 continue; 658 crtc_to_box(&newbox, crtc); 659 } 660 RegionInit(&new_crtc_region, &newbox, 1); 661 RegionUnion(&total_region, &total_region, &new_crtc_region); 662 } 663 664 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 665 rrScrPrivPtr slave_priv = rrGetScrPriv(slave); 666 667 if (!slave->is_output_slave) 668 continue; 669 670 for (c = 0; c < slave_priv->numCrtcs; c++) { 671 RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; 672 673 if (slave_crtc == rr_crtc) { 674 newbox.x1 = x; 675 newbox.y1 = y; 676 if (rotation == RR_Rotate_90 || 677 rotation == RR_Rotate_270) { 678 newbox.x2 = x + h; 679 newbox.y2 = y + w; 680 } else { 681 newbox.x2 = x + w; 682 newbox.y2 = y + h; 683 } 684 } 685 else { 686 if (!slave_crtc->mode) 687 continue; 688 crtc_to_box(&newbox, slave_crtc); 689 } 690 RegionInit(&new_crtc_region, &newbox, 1); 691 RegionUnion(&total_region, &total_region, &new_crtc_region); 692 } 693 } 694 695 newsize = RegionExtents(&total_region); 696 new_width = newsize->x2; 697 new_height = newsize->y2; 698 699 if (new_width < screen_pixmap->drawable.width) 700 new_width = screen_pixmap->drawable.width; 701 702 if (new_height < screen_pixmap->drawable.height) 703 new_height = screen_pixmap->drawable.height; 704 705 if (new_width <= screen_pixmap->drawable.width && 706 new_height <= screen_pixmap->drawable.height) { 707 } else { 708 pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0); 709 } 710 711 /* set shatters TODO */ 712 return TRUE; 713} 714 715/* 716 * Request that the Crtc be reconfigured 717 */ 718Bool 719RRCrtcSet(RRCrtcPtr crtc, 720 RRModePtr mode, 721 int x, 722 int y, Rotation rotation, int numOutputs, RROutputPtr * outputs) 723{ 724 ScreenPtr pScreen = crtc->pScreen; 725 Bool ret = FALSE; 726 Bool recompute = TRUE; 727 Bool crtcChanged; 728 int o; 729 730 rrScrPriv(pScreen); 731 732 crtcChanged = FALSE; 733 for (o = 0; o < numOutputs; o++) { 734 if (outputs[o] && outputs[o]->crtc != crtc) { 735 crtcChanged = TRUE; 736 break; 737 } 738 } 739 740 /* See if nothing changed */ 741 if (crtc->mode == mode && 742 crtc->x == x && 743 crtc->y == y && 744 crtc->rotation == rotation && 745 crtc->numOutputs == numOutputs && 746 !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) && 747 !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) && 748 !crtcChanged) { 749 recompute = FALSE; 750 ret = TRUE; 751 } 752 else { 753 if (pScreen->isGPU) { 754 ScreenPtr master = pScreen->current_master; 755 int width = 0, height = 0; 756 757 if (mode) { 758 width = mode->mode.width; 759 height = mode->mode.height; 760 } 761 ret = rrCheckPixmapBounding(master, crtc, 762 rotation, x, y, width, height); 763 if (!ret) 764 return FALSE; 765 766 if (pScreen->current_master) { 767 Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs); 768 ret = rrSetupPixmapSharing(crtc, width, height, 769 x, y, rotation, sync, 770 numOutputs, outputs); 771 } 772 } 773#if RANDR_12_INTERFACE 774 if (pScrPriv->rrCrtcSet) { 775 ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 776 rotation, numOutputs, outputs); 777 } 778 else 779#endif 780 { 781#if RANDR_10_INTERFACE 782 if (pScrPriv->rrSetConfig) { 783 RRScreenSize size; 784 RRScreenRate rate; 785 786 if (!mode) { 787 RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL); 788 ret = TRUE; 789 } 790 else { 791 size.width = mode->mode.width; 792 size.height = mode->mode.height; 793 if (outputs[0]->mmWidth && outputs[0]->mmHeight) { 794 size.mmWidth = outputs[0]->mmWidth; 795 size.mmHeight = outputs[0]->mmHeight; 796 } 797 else { 798 size.mmWidth = pScreen->mmWidth; 799 size.mmHeight = pScreen->mmHeight; 800 } 801 size.nRates = 1; 802 rate.rate = RRVerticalRefresh(&mode->mode); 803 size.pRates = &rate; 804 ret = 805 (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, 806 &size); 807 /* 808 * Old 1.0 interface tied screen size to mode size 809 */ 810 if (ret) { 811 RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1, 812 outputs); 813 RRScreenSizeNotify(pScreen); 814 } 815 } 816 } 817#endif 818 } 819 if (ret) { 820 821 RRTellChanged(pScreen); 822 823 for (o = 0; o < numOutputs; o++) 824 RRPostPendingProperties(outputs[o]); 825 } 826 } 827 828 if (recompute) 829 RRComputeContiguity(pScreen); 830 831 return ret; 832} 833 834/* 835 * Return crtc transform 836 */ 837RRTransformPtr 838RRCrtcGetTransform(RRCrtcPtr crtc) 839{ 840 RRTransformPtr transform = &crtc->client_pending_transform; 841 842 if (pixman_transform_is_identity(&transform->transform)) 843 return NULL; 844 return transform; 845} 846 847/* 848 * Check whether the pending and current transforms are the same 849 */ 850Bool 851RRCrtcPendingTransform(RRCrtcPtr crtc) 852{ 853 return !RRTransformEqual(&crtc->client_current_transform, 854 &crtc->client_pending_transform); 855} 856 857/* 858 * Destroy a Crtc at shutdown 859 */ 860void 861RRCrtcDestroy(RRCrtcPtr crtc) 862{ 863 FreeResource(crtc->id, 0); 864} 865 866static int 867RRCrtcDestroyResource(void *value, XID pid) 868{ 869 RRCrtcPtr crtc = (RRCrtcPtr) value; 870 ScreenPtr pScreen = crtc->pScreen; 871 872 if (pScreen) { 873 rrScrPriv(pScreen); 874 int i; 875 RRLeasePtr lease, next; 876 877 xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) { 878 int c; 879 for (c = 0; c < lease->numCrtcs; c++) { 880 if (lease->crtcs[c] == crtc) { 881 RRTerminateLease(lease); 882 break; 883 } 884 } 885 } 886 887 for (i = 0; i < pScrPriv->numCrtcs; i++) { 888 if (pScrPriv->crtcs[i] == crtc) { 889 memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 890 (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr)); 891 --pScrPriv->numCrtcs; 892 break; 893 } 894 } 895 896 RRResourcesChanged(pScreen); 897 } 898 899 if (crtc->scanout_pixmap) 900 RRCrtcDetachScanoutPixmap(crtc); 901 free(crtc->gammaRed); 902 if (crtc->mode) 903 RRModeDestroy(crtc->mode); 904 free(crtc->outputs); 905 free(crtc); 906 return 1; 907} 908 909/* 910 * Request that the Crtc gamma be changed 911 */ 912 913Bool 914RRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue) 915{ 916 Bool ret = TRUE; 917 918#if RANDR_12_INTERFACE 919 ScreenPtr pScreen = crtc->pScreen; 920#endif 921 922 memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16)); 923 memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16)); 924 memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16)); 925#if RANDR_12_INTERFACE 926 if (pScreen) { 927 rrScrPriv(pScreen); 928 if (pScrPriv->rrCrtcSetGamma) 929 ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 930 } 931#endif 932 return ret; 933} 934 935/* 936 * Request current gamma back from the DDX (if possible). 937 * This includes gamma size. 938 */ 939Bool 940RRCrtcGammaGet(RRCrtcPtr crtc) 941{ 942 Bool ret = TRUE; 943 944#if RANDR_12_INTERFACE 945 ScreenPtr pScreen = crtc->pScreen; 946#endif 947 948#if RANDR_12_INTERFACE 949 if (pScreen) { 950 rrScrPriv(pScreen); 951 if (pScrPriv->rrCrtcGetGamma) 952 ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 953 } 954#endif 955 return ret; 956} 957 958/* 959 * Notify the extension that the Crtc gamma has been changed 960 * The driver calls this whenever it has changed the gamma values 961 * in the RRCrtcRec 962 */ 963 964Bool 965RRCrtcGammaNotify(RRCrtcPtr crtc) 966{ 967 return TRUE; /* not much going on here */ 968} 969 970static void 971RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform, 972 int *width, int *height) 973{ 974 BoxRec box; 975 976 if (mode == NULL) { 977 *width = 0; 978 *height = 0; 979 return; 980 } 981 982 box.x1 = 0; 983 box.y1 = 0; 984 box.x2 = mode->mode.width; 985 box.y2 = mode->mode.height; 986 987 pixman_transform_bounds(transform, &box); 988 *width = box.x2 - box.x1; 989 *height = box.y2 - box.y1; 990} 991 992/** 993 * Returns the width/height that the crtc scans out from the framebuffer 994 */ 995void 996RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 997{ 998 RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height); 999} 1000 1001/* 1002 * Set the size of the gamma table at server startup time 1003 */ 1004 1005Bool 1006RRCrtcGammaSetSize(RRCrtcPtr crtc, int size) 1007{ 1008 CARD16 *gamma; 1009 1010 if (size == crtc->gammaSize) 1011 return TRUE; 1012 if (size) { 1013 gamma = xallocarray(size, 3 * sizeof(CARD16)); 1014 if (!gamma) 1015 return FALSE; 1016 } 1017 else 1018 gamma = NULL; 1019 free(crtc->gammaRed); 1020 crtc->gammaRed = gamma; 1021 crtc->gammaGreen = gamma + size; 1022 crtc->gammaBlue = gamma + size * 2; 1023 crtc->gammaSize = size; 1024 return TRUE; 1025} 1026 1027/* 1028 * Set the pending CRTC transformation 1029 */ 1030 1031int 1032RRCrtcTransformSet(RRCrtcPtr crtc, 1033 PictTransformPtr transform, 1034 struct pixman_f_transform *f_transform, 1035 struct pixman_f_transform *f_inverse, 1036 char *filter_name, 1037 int filter_len, xFixed * params, int nparams) 1038{ 1039 PictFilterPtr filter = NULL; 1040 int width = 0, height = 0; 1041 1042 if (!crtc->transforms) 1043 return BadValue; 1044 1045 if (filter_len) { 1046 filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len); 1047 if (!filter) 1048 return BadName; 1049 if (filter->ValidateParams) { 1050 if (!filter->ValidateParams(crtc->pScreen, filter->id, 1051 params, nparams, &width, &height)) 1052 return BadMatch; 1053 } 1054 else { 1055 width = filter->width; 1056 height = filter->height; 1057 } 1058 } 1059 else { 1060 if (nparams) 1061 return BadMatch; 1062 } 1063 if (!RRTransformSetFilter(&crtc->client_pending_transform, 1064 filter, params, nparams, width, height)) 1065 return BadAlloc; 1066 1067 crtc->client_pending_transform.transform = *transform; 1068 crtc->client_pending_transform.f_transform = *f_transform; 1069 crtc->client_pending_transform.f_inverse = *f_inverse; 1070 return Success; 1071} 1072 1073/* 1074 * Initialize crtc type 1075 */ 1076Bool 1077RRCrtcInit(void) 1078{ 1079 RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC"); 1080 if (!RRCrtcType) 1081 return FALSE; 1082 1083 return TRUE; 1084} 1085 1086/* 1087 * Initialize crtc type error value 1088 */ 1089void 1090RRCrtcInitErrorValue(void) 1091{ 1092 SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 1093} 1094 1095int 1096ProcRRGetCrtcInfo(ClientPtr client) 1097{ 1098 REQUEST(xRRGetCrtcInfoReq); 1099 xRRGetCrtcInfoReply rep; 1100 RRCrtcPtr crtc; 1101 CARD8 *extra = NULL; 1102 unsigned long extraLen; 1103 ScreenPtr pScreen; 1104 rrScrPrivPtr pScrPriv; 1105 RRModePtr mode; 1106 RROutput *outputs; 1107 RROutput *possible; 1108 int i, j, k; 1109 int width, height; 1110 BoxRec panned_area; 1111 Bool leased; 1112 1113 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 1114 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1115 1116 leased = RRCrtcIsLeased(crtc); 1117 1118 /* All crtcs must be associated with screens before client 1119 * requests are processed 1120 */ 1121 pScreen = crtc->pScreen; 1122 pScrPriv = rrGetScrPriv(pScreen); 1123 1124 mode = crtc->mode; 1125 1126 rep = (xRRGetCrtcInfoReply) { 1127 .type = X_Reply, 1128 .status = RRSetConfigSuccess, 1129 .sequenceNumber = client->sequence, 1130 .length = 0, 1131 .timestamp = pScrPriv->lastSetTime.milliseconds 1132 }; 1133 if (leased) { 1134 rep.x = rep.y = rep.width = rep.height = 0; 1135 rep.mode = 0; 1136 rep.rotation = RR_Rotate_0; 1137 rep.rotations = RR_Rotate_0; 1138 rep.nOutput = 0; 1139 rep.nPossibleOutput = 0; 1140 rep.length = 0; 1141 extraLen = 0; 1142 } else { 1143 if (pScrPriv->rrGetPanning && 1144 pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) && 1145 (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 1146 { 1147 rep.x = panned_area.x1; 1148 rep.y = panned_area.y1; 1149 rep.width = panned_area.x2 - panned_area.x1; 1150 rep.height = panned_area.y2 - panned_area.y1; 1151 } 1152 else { 1153 RRCrtcGetScanoutSize(crtc, &width, &height); 1154 rep.x = crtc->x; 1155 rep.y = crtc->y; 1156 rep.width = width; 1157 rep.height = height; 1158 } 1159 rep.mode = mode ? mode->mode.id : 0; 1160 rep.rotation = crtc->rotation; 1161 rep.rotations = crtc->rotations; 1162 rep.nOutput = crtc->numOutputs; 1163 k = 0; 1164 for (i = 0; i < pScrPriv->numOutputs; i++) { 1165 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1166 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1167 if (pScrPriv->outputs[i]->crtcs[j] == crtc) 1168 k++; 1169 } 1170 } 1171 1172 rep.nPossibleOutput = k; 1173 1174 rep.length = rep.nOutput + rep.nPossibleOutput; 1175 1176 extraLen = rep.length << 2; 1177 if (extraLen) { 1178 extra = malloc(extraLen); 1179 if (!extra) 1180 return BadAlloc; 1181 } 1182 1183 outputs = (RROutput *) extra; 1184 possible = (RROutput *) (outputs + rep.nOutput); 1185 1186 for (i = 0; i < crtc->numOutputs; i++) { 1187 outputs[i] = crtc->outputs[i]->id; 1188 if (client->swapped) 1189 swapl(&outputs[i]); 1190 } 1191 k = 0; 1192 for (i = 0; i < pScrPriv->numOutputs; i++) { 1193 if (!RROutputIsLeased(pScrPriv->outputs[i])) { 1194 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 1195 if (pScrPriv->outputs[i]->crtcs[j] == crtc) { 1196 possible[k] = pScrPriv->outputs[i]->id; 1197 if (client->swapped) 1198 swapl(&possible[k]); 1199 k++; 1200 } 1201 } 1202 } 1203 } 1204 1205 if (client->swapped) { 1206 swaps(&rep.sequenceNumber); 1207 swapl(&rep.length); 1208 swapl(&rep.timestamp); 1209 swaps(&rep.x); 1210 swaps(&rep.y); 1211 swaps(&rep.width); 1212 swaps(&rep.height); 1213 swapl(&rep.mode); 1214 swaps(&rep.rotation); 1215 swaps(&rep.rotations); 1216 swaps(&rep.nOutput); 1217 swaps(&rep.nPossibleOutput); 1218 } 1219 WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep); 1220 if (extraLen) { 1221 WriteToClient(client, extraLen, extra); 1222 free(extra); 1223 } 1224 1225 return Success; 1226} 1227 1228int 1229ProcRRSetCrtcConfig(ClientPtr client) 1230{ 1231 REQUEST(xRRSetCrtcConfigReq); 1232 xRRSetCrtcConfigReply rep; 1233 ScreenPtr pScreen; 1234 rrScrPrivPtr pScrPriv; 1235 RRCrtcPtr crtc; 1236 RRModePtr mode; 1237 int numOutputs; 1238 RROutputPtr *outputs = NULL; 1239 RROutput *outputIds; 1240 TimeStamp time; 1241 Rotation rotation; 1242 int ret, i, j; 1243 CARD8 status; 1244 1245 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 1246 numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq))); 1247 1248 VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 1249 1250 if (RRCrtcIsLeased(crtc)) 1251 return BadAccess; 1252 1253 if (stuff->mode == None) { 1254 mode = NULL; 1255 if (numOutputs > 0) 1256 return BadMatch; 1257 } 1258 else { 1259 VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 1260 if (numOutputs == 0) 1261 return BadMatch; 1262 } 1263 if (numOutputs) { 1264 outputs = xallocarray(numOutputs, sizeof(RROutputPtr)); 1265 if (!outputs) 1266 return BadAlloc; 1267 } 1268 else 1269 outputs = NULL; 1270 1271 outputIds = (RROutput *) (stuff + 1); 1272 for (i = 0; i < numOutputs; i++) { 1273 ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i], 1274 RROutputType, client, DixSetAttrAccess); 1275 if (ret != Success) { 1276 free(outputs); 1277 return ret; 1278 } 1279 1280 if (RROutputIsLeased(outputs[i])) { 1281 free(outputs); 1282 return BadAccess; 1283 } 1284 1285 /* validate crtc for this output */ 1286 for (j = 0; j < outputs[i]->numCrtcs; j++) 1287 if (outputs[i]->crtcs[j] == crtc) 1288 break; 1289 if (j == outputs[i]->numCrtcs) { 1290 free(outputs); 1291 return BadMatch; 1292 } 1293 /* validate mode for this output */ 1294 for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) { 1295 RRModePtr m = (j < outputs[i]->numModes ? 1296 outputs[i]->modes[j] : 1297 outputs[i]->userModes[j - outputs[i]->numModes]); 1298 if (m == mode) 1299 break; 1300 } 1301 if (j == outputs[i]->numModes + outputs[i]->numUserModes) { 1302 free(outputs); 1303 return BadMatch; 1304 } 1305 } 1306 /* validate clones */ 1307 for (i = 0; i < numOutputs; i++) { 1308 for (j = 0; j < numOutputs; j++) { 1309 int k; 1310 1311 if (i == j) 1312 continue; 1313 for (k = 0; k < outputs[i]->numClones; k++) { 1314 if (outputs[i]->clones[k] == outputs[j]) 1315 break; 1316 } 1317 if (k == outputs[i]->numClones) { 1318 free(outputs); 1319 return BadMatch; 1320 } 1321 } 1322 } 1323 1324 pScreen = crtc->pScreen; 1325 pScrPriv = rrGetScrPriv(pScreen); 1326 1327 time = ClientTimeToServerTime(stuff->timestamp); 1328 1329 if (!pScrPriv) { 1330 time = currentTime; 1331 status = RRSetConfigFailed; 1332 goto sendReply; 1333 } 1334 1335 /* 1336 * Validate requested rotation 1337 */ 1338 rotation = (Rotation) stuff->rotation; 1339 1340 /* test the rotation bits only! */ 1341 switch (rotation & 0xf) { 1342 case RR_Rotate_0: 1343 case RR_Rotate_90: 1344 case RR_Rotate_180: 1345 case RR_Rotate_270: 1346 break; 1347 default: 1348 /* 1349 * Invalid rotation 1350 */ 1351 client->errorValue = stuff->rotation; 1352 free(outputs); 1353 return BadValue; 1354 } 1355 1356 if (mode) { 1357 if ((~crtc->rotations) & rotation) { 1358 /* 1359 * requested rotation or reflection not supported by screen 1360 */ 1361 client->errorValue = stuff->rotation; 1362 free(outputs); 1363 return BadMatch; 1364 } 1365 1366#ifdef RANDR_12_INTERFACE 1367 /* 1368 * Check screen size bounds if the DDX provides a 1.2 interface 1369 * for setting screen size. Else, assume the CrtcSet sets 1370 * the size along with the mode. If the driver supports transforms, 1371 * then it must allow crtcs to display a subset of the screen, so 1372 * only do this check for drivers without transform support. 1373 */ 1374 if (pScrPriv->rrScreenSetSize && !crtc->transforms) { 1375 int source_width; 1376 int source_height; 1377 PictTransform transform; 1378 struct pixman_f_transform f_transform, f_inverse; 1379 int width, height; 1380 1381 if (pScreen->isGPU) { 1382 width = pScreen->current_master->width; 1383 height = pScreen->current_master->height; 1384 } 1385 else { 1386 width = pScreen->width; 1387 height = pScreen->height; 1388 } 1389 1390 RRTransformCompute(stuff->x, stuff->y, 1391 mode->mode.width, mode->mode.height, 1392 rotation, 1393 &crtc->client_pending_transform, 1394 &transform, &f_transform, &f_inverse); 1395 1396 RRModeGetScanoutSize(mode, &transform, &source_width, 1397 &source_height); 1398 if (stuff->x + source_width > width) { 1399 client->errorValue = stuff->x; 1400 free(outputs); 1401 return BadValue; 1402 } 1403 1404 if (stuff->y + source_height > height) { 1405 client->errorValue = stuff->y; 1406 free(outputs); 1407 return BadValue; 1408 } 1409 } 1410#endif 1411 } 1412 1413 if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y, 1414 rotation, numOutputs, outputs)) { 1415 status = RRSetConfigFailed; 1416 goto sendReply; 1417 } 1418 status = RRSetConfigSuccess; 1419 pScrPriv->lastSetTime = time; 1420 1421 sendReply: 1422 free(outputs); 1423 1424 rep = (xRRSetCrtcConfigReply) { 1425 .type = X_Reply, 1426 .status = status, 1427 .sequenceNumber = client->sequence, 1428 .length = 0, 1429 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1430 }; 1431 1432 if (client->swapped) { 1433 swaps(&rep.sequenceNumber); 1434 swapl(&rep.length); 1435 swapl(&rep.newTimestamp); 1436 } 1437 WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep); 1438 1439 return Success; 1440} 1441 1442int 1443ProcRRGetPanning(ClientPtr client) 1444{ 1445 REQUEST(xRRGetPanningReq); 1446 xRRGetPanningReply rep; 1447 RRCrtcPtr crtc; 1448 ScreenPtr pScreen; 1449 rrScrPrivPtr pScrPriv; 1450 BoxRec total; 1451 BoxRec tracking; 1452 INT16 border[4]; 1453 1454 REQUEST_SIZE_MATCH(xRRGetPanningReq); 1455 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1456 1457 /* All crtcs must be associated with screens before client 1458 * requests are processed 1459 */ 1460 pScreen = crtc->pScreen; 1461 pScrPriv = rrGetScrPriv(pScreen); 1462 1463 if (!pScrPriv) 1464 return RRErrorBase + BadRRCrtc; 1465 1466 rep = (xRRGetPanningReply) { 1467 .type = X_Reply, 1468 .status = RRSetConfigSuccess, 1469 .sequenceNumber = client->sequence, 1470 .length = 1, 1471 .timestamp = pScrPriv->lastSetTime.milliseconds 1472 }; 1473 1474 if (pScrPriv->rrGetPanning && 1475 pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) { 1476 rep.left = total.x1; 1477 rep.top = total.y1; 1478 rep.width = total.x2 - total.x1; 1479 rep.height = total.y2 - total.y1; 1480 rep.track_left = tracking.x1; 1481 rep.track_top = tracking.y1; 1482 rep.track_width = tracking.x2 - tracking.x1; 1483 rep.track_height = tracking.y2 - tracking.y1; 1484 rep.border_left = border[0]; 1485 rep.border_top = border[1]; 1486 rep.border_right = border[2]; 1487 rep.border_bottom = border[3]; 1488 } 1489 1490 if (client->swapped) { 1491 swaps(&rep.sequenceNumber); 1492 swapl(&rep.length); 1493 swapl(&rep.timestamp); 1494 swaps(&rep.left); 1495 swaps(&rep.top); 1496 swaps(&rep.width); 1497 swaps(&rep.height); 1498 swaps(&rep.track_left); 1499 swaps(&rep.track_top); 1500 swaps(&rep.track_width); 1501 swaps(&rep.track_height); 1502 swaps(&rep.border_left); 1503 swaps(&rep.border_top); 1504 swaps(&rep.border_right); 1505 swaps(&rep.border_bottom); 1506 } 1507 WriteToClient(client, sizeof(xRRGetPanningReply), &rep); 1508 return Success; 1509} 1510 1511int 1512ProcRRSetPanning(ClientPtr client) 1513{ 1514 REQUEST(xRRSetPanningReq); 1515 xRRSetPanningReply rep; 1516 RRCrtcPtr crtc; 1517 ScreenPtr pScreen; 1518 rrScrPrivPtr pScrPriv; 1519 TimeStamp time; 1520 BoxRec total; 1521 BoxRec tracking; 1522 INT16 border[4]; 1523 CARD8 status; 1524 1525 REQUEST_SIZE_MATCH(xRRSetPanningReq); 1526 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1527 1528 if (RRCrtcIsLeased(crtc)) 1529 return BadAccess; 1530 1531 /* All crtcs must be associated with screens before client 1532 * requests are processed 1533 */ 1534 pScreen = crtc->pScreen; 1535 pScrPriv = rrGetScrPriv(pScreen); 1536 1537 if (!pScrPriv) { 1538 time = currentTime; 1539 status = RRSetConfigFailed; 1540 goto sendReply; 1541 } 1542 1543 time = ClientTimeToServerTime(stuff->timestamp); 1544 1545 if (!pScrPriv->rrGetPanning) 1546 return RRErrorBase + BadRRCrtc; 1547 1548 total.x1 = stuff->left; 1549 total.y1 = stuff->top; 1550 total.x2 = total.x1 + stuff->width; 1551 total.y2 = total.y1 + stuff->height; 1552 tracking.x1 = stuff->track_left; 1553 tracking.y1 = stuff->track_top; 1554 tracking.x2 = tracking.x1 + stuff->track_width; 1555 tracking.y2 = tracking.y1 + stuff->track_height; 1556 border[0] = stuff->border_left; 1557 border[1] = stuff->border_top; 1558 border[2] = stuff->border_right; 1559 border[3] = stuff->border_bottom; 1560 1561 if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border)) 1562 return BadMatch; 1563 1564 pScrPriv->lastSetTime = time; 1565 1566 status = RRSetConfigSuccess; 1567 1568 sendReply: 1569 rep = (xRRSetPanningReply) { 1570 .type = X_Reply, 1571 .status = status, 1572 .sequenceNumber = client->sequence, 1573 .length = 0, 1574 .newTimestamp = pScrPriv->lastSetTime.milliseconds 1575 }; 1576 1577 if (client->swapped) { 1578 swaps(&rep.sequenceNumber); 1579 swapl(&rep.length); 1580 swapl(&rep.newTimestamp); 1581 } 1582 WriteToClient(client, sizeof(xRRSetPanningReply), &rep); 1583 return Success; 1584} 1585 1586int 1587ProcRRGetCrtcGammaSize(ClientPtr client) 1588{ 1589 REQUEST(xRRGetCrtcGammaSizeReq); 1590 xRRGetCrtcGammaSizeReply reply; 1591 RRCrtcPtr crtc; 1592 1593 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 1594 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1595 1596 /* Gamma retrieval failed, any better error? */ 1597 if (!RRCrtcGammaGet(crtc)) 1598 return RRErrorBase + BadRRCrtc; 1599 1600 reply = (xRRGetCrtcGammaSizeReply) { 1601 .type = X_Reply, 1602 .sequenceNumber = client->sequence, 1603 .length = 0, 1604 .size = crtc->gammaSize 1605 }; 1606 if (client->swapped) { 1607 swaps(&reply.sequenceNumber); 1608 swapl(&reply.length); 1609 swaps(&reply.size); 1610 } 1611 WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply); 1612 return Success; 1613} 1614 1615int 1616ProcRRGetCrtcGamma(ClientPtr client) 1617{ 1618 REQUEST(xRRGetCrtcGammaReq); 1619 xRRGetCrtcGammaReply reply; 1620 RRCrtcPtr crtc; 1621 unsigned long len; 1622 char *extra = NULL; 1623 1624 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 1625 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1626 1627 /* Gamma retrieval failed, any better error? */ 1628 if (!RRCrtcGammaGet(crtc)) 1629 return RRErrorBase + BadRRCrtc; 1630 1631 len = crtc->gammaSize * 3 * 2; 1632 1633 if (crtc->gammaSize) { 1634 extra = malloc(len); 1635 if (!extra) 1636 return BadAlloc; 1637 } 1638 1639 reply = (xRRGetCrtcGammaReply) { 1640 .type = X_Reply, 1641 .sequenceNumber = client->sequence, 1642 .length = bytes_to_int32(len), 1643 .size = crtc->gammaSize 1644 }; 1645 if (client->swapped) { 1646 swaps(&reply.sequenceNumber); 1647 swapl(&reply.length); 1648 swaps(&reply.size); 1649 } 1650 WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply); 1651 if (crtc->gammaSize) { 1652 memcpy(extra, crtc->gammaRed, len); 1653 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1654 WriteSwappedDataToClient(client, len, extra); 1655 free(extra); 1656 } 1657 return Success; 1658} 1659 1660int 1661ProcRRSetCrtcGamma(ClientPtr client) 1662{ 1663 REQUEST(xRRSetCrtcGammaReq); 1664 RRCrtcPtr crtc; 1665 unsigned long len; 1666 CARD16 *red, *green, *blue; 1667 1668 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 1669 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1670 1671 if (RRCrtcIsLeased(crtc)) 1672 return BadAccess; 1673 1674 len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq)); 1675 if (len < (stuff->size * 3 + 1) >> 1) 1676 return BadLength; 1677 1678 if (stuff->size != crtc->gammaSize) 1679 return BadMatch; 1680 1681 red = (CARD16 *) (stuff + 1); 1682 green = red + crtc->gammaSize; 1683 blue = green + crtc->gammaSize; 1684 1685 RRCrtcGammaSet(crtc, red, green, blue); 1686 1687 return Success; 1688} 1689 1690/* Version 1.3 additions */ 1691 1692int 1693ProcRRSetCrtcTransform(ClientPtr client) 1694{ 1695 REQUEST(xRRSetCrtcTransformReq); 1696 RRCrtcPtr crtc; 1697 PictTransform transform; 1698 struct pixman_f_transform f_transform, f_inverse; 1699 char *filter; 1700 int nbytes; 1701 xFixed *params; 1702 int nparams; 1703 1704 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 1705 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1706 1707 if (RRCrtcIsLeased(crtc)) 1708 return BadAccess; 1709 1710 PictTransform_from_xRenderTransform(&transform, &stuff->transform); 1711 pixman_f_transform_from_pixman_transform(&f_transform, &transform); 1712 if (!pixman_f_transform_invert(&f_inverse, &f_transform)) 1713 return BadMatch; 1714 1715 filter = (char *) (stuff + 1); 1716 nbytes = stuff->nbytesFilter; 1717 params = (xFixed *) (filter + pad_to_int32(nbytes)); 1718 nparams = ((xFixed *) stuff + client->req_len) - params; 1719 if (nparams < 0) 1720 return BadLength; 1721 1722 return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse, 1723 filter, nbytes, params, nparams); 1724} 1725 1726#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 1727 1728static int 1729transform_filter_length(RRTransformPtr transform) 1730{ 1731 int nbytes, nparams; 1732 1733 if (transform->filter == NULL) 1734 return 0; 1735 nbytes = strlen(transform->filter->name); 1736 nparams = transform->nparams; 1737 return pad_to_int32(nbytes) + (nparams * sizeof(xFixed)); 1738} 1739 1740static int 1741transform_filter_encode(ClientPtr client, char *output, 1742 CARD16 *nbytesFilter, 1743 CARD16 *nparamsFilter, RRTransformPtr transform) 1744{ 1745 int nbytes, nparams; 1746 1747 if (transform->filter == NULL) { 1748 *nbytesFilter = 0; 1749 *nparamsFilter = 0; 1750 return 0; 1751 } 1752 nbytes = strlen(transform->filter->name); 1753 nparams = transform->nparams; 1754 *nbytesFilter = nbytes; 1755 *nparamsFilter = nparams; 1756 memcpy(output, transform->filter->name, nbytes); 1757 while ((nbytes & 3) != 0) 1758 output[nbytes++] = 0; 1759 memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed)); 1760 if (client->swapped) { 1761 swaps(nbytesFilter); 1762 swaps(nparamsFilter); 1763 SwapLongs((CARD32 *) (output + nbytes), nparams); 1764 } 1765 nbytes += nparams * sizeof(xFixed); 1766 return nbytes; 1767} 1768 1769static void 1770transform_encode(ClientPtr client, xRenderTransform * wire, 1771 PictTransform * pict) 1772{ 1773 xRenderTransform_from_PictTransform(wire, pict); 1774 if (client->swapped) 1775 SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 1776} 1777 1778int 1779ProcRRGetCrtcTransform(ClientPtr client) 1780{ 1781 REQUEST(xRRGetCrtcTransformReq); 1782 xRRGetCrtcTransformReply *reply; 1783 RRCrtcPtr crtc; 1784 int nextra; 1785 RRTransformPtr current, pending; 1786 char *extra; 1787 1788 REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq); 1789 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1790 1791 pending = &crtc->client_pending_transform; 1792 current = &crtc->client_current_transform; 1793 1794 nextra = (transform_filter_length(pending) + 1795 transform_filter_length(current)); 1796 1797 reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra); 1798 if (!reply) 1799 return BadAlloc; 1800 1801 extra = (char *) (reply + 1); 1802 reply->type = X_Reply; 1803 reply->sequenceNumber = client->sequence; 1804 reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 1805 1806 reply->hasTransforms = crtc->transforms; 1807 1808 transform_encode(client, &reply->pendingTransform, &pending->transform); 1809 extra += transform_filter_encode(client, extra, 1810 &reply->pendingNbytesFilter, 1811 &reply->pendingNparamsFilter, pending); 1812 1813 transform_encode(client, &reply->currentTransform, ¤t->transform); 1814 extra += transform_filter_encode(client, extra, 1815 &reply->currentNbytesFilter, 1816 &reply->currentNparamsFilter, current); 1817 1818 if (client->swapped) { 1819 swaps(&reply->sequenceNumber); 1820 swapl(&reply->length); 1821 } 1822 WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply); 1823 free(reply); 1824 return Success; 1825} 1826 1827static Bool 1828check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y) 1829{ 1830 rrScrPriv(pScreen); 1831 int i; 1832 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1833 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1834 1835 int left, right, top, bottom; 1836 1837 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1838 continue; 1839 1840 if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom)) 1841 return TRUE; 1842 } 1843 return FALSE; 1844} 1845 1846static Bool 1847constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y) 1848{ 1849 rrScrPriv(pScreen); 1850 int i; 1851 1852 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1853 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1854 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1855 int nx, ny; 1856 int left, right, top, bottom; 1857 1858 if (!cursor_bounds(crtc, &left, &right, &top, &bottom)) 1859 continue; 1860 1861 miPointerGetPosition(pDev, &nx, &ny); 1862 1863 if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) { 1864 if (*x < left) 1865 *x = left; 1866 if (*x >= right) 1867 *x = right - 1; 1868 if (*y < top) 1869 *y = top; 1870 if (*y >= bottom) 1871 *y = bottom - 1; 1872 1873 return TRUE; 1874 } 1875 } 1876 return FALSE; 1877} 1878 1879void 1880RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, 1881 int *y) 1882{ 1883 rrScrPriv(pScreen); 1884 Bool ret; 1885 ScreenPtr slave; 1886 1887 /* intentional dead space -> let it float */ 1888 if (pScrPriv->discontiguous) 1889 return; 1890 1891 /* if we're moving inside a crtc, we're fine */ 1892 ret = check_all_screen_crtcs(pScreen, x, y); 1893 if (ret == TRUE) 1894 return; 1895 1896 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 1897 if (!slave->is_output_slave) 1898 continue; 1899 1900 ret = check_all_screen_crtcs(slave, x, y); 1901 if (ret == TRUE) 1902 return; 1903 } 1904 1905 /* if we're trying to escape, clamp to the CRTC we're coming from */ 1906 ret = constrain_all_screen_crtcs(pDev, pScreen, x, y); 1907 if (ret == TRUE) 1908 return; 1909 1910 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { 1911 if (!slave->is_output_slave) 1912 continue; 1913 1914 ret = constrain_all_screen_crtcs(pDev, slave, x, y); 1915 if (ret == TRUE) 1916 return; 1917 } 1918} 1919 1920Bool 1921RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable) 1922{ 1923 rrScrPriv(pDrawable->pScreen); 1924 Bool ret = TRUE; 1925 PixmapPtr *saved_scanout_pixmap; 1926 int i; 1927 1928 saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs); 1929 if (saved_scanout_pixmap == NULL) 1930 return FALSE; 1931 1932 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1933 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1934 Bool size_fits; 1935 1936 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 1937 1938 if (!crtc->mode && enable) 1939 continue; 1940 if (!crtc->scanout_pixmap && !enable) 1941 continue; 1942 1943 /* not supported with double buffering, needs ABI change for 2 ppix */ 1944 if (crtc->scanout_pixmap_back) { 1945 ret = FALSE; 1946 continue; 1947 } 1948 1949 size_fits = (crtc->mode && 1950 crtc->x == pDrawable->x && 1951 crtc->y == pDrawable->y && 1952 crtc->mode->mode.width == pDrawable->width && 1953 crtc->mode->mode.height == pDrawable->height); 1954 1955 /* is the pixmap already set? */ 1956 if (crtc->scanout_pixmap == pPixmap) { 1957 /* if its a disable then don't care about size */ 1958 if (enable == FALSE) { 1959 /* set scanout to NULL */ 1960 crtc->scanout_pixmap = NULL; 1961 } 1962 else if (!size_fits) { 1963 /* if the size no longer fits then drop off */ 1964 crtc->scanout_pixmap = NULL; 1965 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 1966 1967 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 1968 crtc->rotation, crtc->numOutputs, crtc->outputs); 1969 saved_scanout_pixmap[i] = crtc->scanout_pixmap; 1970 ret = FALSE; 1971 } 1972 else { 1973 /* if the size fits then we are already setup */ 1974 } 1975 } 1976 else { 1977 if (!size_fits) 1978 ret = FALSE; 1979 else if (enable) 1980 crtc->scanout_pixmap = pPixmap; 1981 else 1982 /* reject an attempt to disable someone else's scanout_pixmap */ 1983 ret = FALSE; 1984 } 1985 } 1986 1987 for (i = 0; i < pScrPriv->numCrtcs; i++) { 1988 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 1989 1990 if (crtc->scanout_pixmap == saved_scanout_pixmap[i]) 1991 continue; 1992 1993 if (ret) { 1994 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap); 1995 1996 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y, 1997 crtc->rotation, crtc->numOutputs, crtc->outputs); 1998 } 1999 else 2000 crtc->scanout_pixmap = saved_scanout_pixmap[i]; 2001 } 2002 free(saved_scanout_pixmap); 2003 2004 return ret; 2005} 2006 2007Bool 2008RRHasScanoutPixmap(ScreenPtr pScreen) 2009{ 2010 rrScrPriv(pScreen); 2011 int i; 2012 2013 if (!pScreen->is_output_slave) 2014 return FALSE; 2015 2016 for (i = 0; i < pScrPriv->numCrtcs; i++) { 2017 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 2018 2019 if (crtc->scanout_pixmap) 2020 return TRUE; 2021 } 2022 2023 return FALSE; 2024} 2025