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