1/* 2 * Copyright © 2006 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "randrstr.h" 24#include "swaprep.h" 25 26RESTYPE RRCrtcType; 27 28/* 29 * Notify the CRTC of some change 30 */ 31void 32RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged) 33{ 34 ScreenPtr pScreen = crtc->pScreen; 35 36 crtc->changed = TRUE; 37 if (pScreen) 38 { 39 rrScrPriv(pScreen); 40 41 pScrPriv->changed = TRUE; 42 /* 43 * Send ConfigureNotify on any layout change 44 */ 45 if (layoutChanged) 46 pScrPriv->layoutChanged = TRUE; 47 } 48} 49 50/* 51 * Create a CRTC 52 */ 53RRCrtcPtr 54RRCrtcCreate (ScreenPtr pScreen, void *devPrivate) 55{ 56 RRCrtcPtr crtc; 57 RRCrtcPtr *crtcs; 58 rrScrPrivPtr pScrPriv; 59 60 if (!RRInit()) 61 return NULL; 62 63 pScrPriv = rrGetScrPriv(pScreen); 64 65 /* make space for the crtc pointer */ 66 if (pScrPriv->numCrtcs) 67 crtcs = realloc(pScrPriv->crtcs, 68 (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr)); 69 else 70 crtcs = malloc(sizeof (RRCrtcPtr)); 71 if (!crtcs) 72 return FALSE; 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, (pointer) crtc)) 98 return NULL; 99 100 /* attach the screen and crtc together */ 101 crtc->pScreen = pScreen; 102 pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc; 103 104 return crtc; 105} 106 107/* 108 * Set the allowed rotations on a CRTC 109 */ 110void 111RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations) 112{ 113 crtc->rotations = rotations; 114} 115 116/* 117 * Set whether transforms are allowed on a CRTC 118 */ 119void 120RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms) 121{ 122 crtc->transforms = transforms; 123} 124 125/* 126 * Notify the extension that the Crtc has been reconfigured, 127 * the driver calls this whenever it has updated the mode 128 */ 129Bool 130RRCrtcNotify (RRCrtcPtr crtc, 131 RRModePtr mode, 132 int x, 133 int y, 134 Rotation rotation, 135 RRTransformPtr transform, 136 int numOutputs, 137 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 { 147 for (j = 0; j < crtc->numOutputs; j++) 148 if (outputs[i] == crtc->outputs[j]) 149 break; 150 if (j == crtc->numOutputs) 151 { 152 outputs[i]->crtc = crtc; 153 RROutputChanged (outputs[i], FALSE); 154 RRCrtcChanged (crtc, FALSE); 155 } 156 } 157 /* 158 * Check to see if any of the old outputs are 159 * not in the new list and mark them as changed 160 */ 161 for (j = 0; j < crtc->numOutputs; j++) 162 { 163 for (i = 0; i < numOutputs; i++) 164 if (outputs[i] == crtc->outputs[j]) 165 break; 166 if (i == numOutputs) 167 { 168 if (crtc->outputs[j]->crtc == crtc) 169 crtc->outputs[j]->crtc = NULL; 170 RROutputChanged (crtc->outputs[j], FALSE); 171 RRCrtcChanged (crtc, FALSE); 172 } 173 } 174 /* 175 * Reallocate the crtc output array if necessary 176 */ 177 if (numOutputs != crtc->numOutputs) 178 { 179 RROutputPtr *newoutputs; 180 181 if (numOutputs) 182 { 183 if (crtc->numOutputs) 184 newoutputs = realloc(crtc->outputs, 185 numOutputs * sizeof (RROutputPtr)); 186 else 187 newoutputs = malloc(numOutputs * sizeof (RROutputPtr)); 188 if (!newoutputs) 189 return FALSE; 190 } 191 else 192 { 193 free(crtc->outputs); 194 newoutputs = NULL; 195 } 196 crtc->outputs = newoutputs; 197 crtc->numOutputs = numOutputs; 198 } 199 /* 200 * Copy the new list of outputs into the crtc 201 */ 202 memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)); 203 /* 204 * Update remaining crtc fields 205 */ 206 if (mode != crtc->mode) 207 { 208 if (crtc->mode) 209 RRModeDestroy (crtc->mode); 210 crtc->mode = mode; 211 if (mode != NULL) 212 mode->refcnt++; 213 RRCrtcChanged (crtc, TRUE); 214 } 215 if (x != crtc->x) 216 { 217 crtc->x = x; 218 RRCrtcChanged (crtc, TRUE); 219 } 220 if (y != crtc->y) 221 { 222 crtc->y = y; 223 RRCrtcChanged (crtc, TRUE); 224 } 225 if (rotation != crtc->rotation) 226 { 227 crtc->rotation = rotation; 228 RRCrtcChanged (crtc, TRUE); 229 } 230 if (!RRTransformEqual (transform, &crtc->client_current_transform)) { 231 RRTransformCopy (&crtc->client_current_transform, transform); 232 RRCrtcChanged (crtc, TRUE); 233 } 234 if (crtc->changed && mode) 235 { 236 RRTransformCompute (x, y, 237 mode->mode.width, mode->mode.height, 238 rotation, 239 &crtc->client_current_transform, 240 &crtc->transform, &crtc->f_transform, 241 &crtc->f_inverse); 242 } 243 return TRUE; 244} 245 246void 247RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc) 248{ 249 ScreenPtr pScreen = pWin->drawable.pScreen; 250 rrScrPriv (pScreen); 251 xRRCrtcChangeNotifyEvent ce; 252 RRModePtr mode = crtc->mode; 253 254 ce.type = RRNotify + RREventBase; 255 ce.subCode = RRNotify_CrtcChange; 256 ce.timestamp = pScrPriv->lastSetTime.milliseconds; 257 ce.window = pWin->drawable.id; 258 ce.crtc = crtc->id; 259 ce.rotation = crtc->rotation; 260 if (mode) 261 { 262 ce.mode = mode->mode.id; 263 ce.x = crtc->x; 264 ce.y = crtc->y; 265 ce.width = mode->mode.width; 266 ce.height = mode->mode.height; 267 } 268 else 269 { 270 ce.mode = None; 271 ce.x = 0; 272 ce.y = 0; 273 ce.width = 0; 274 ce.height = 0; 275 } 276 WriteEventsToClient (client, 1, (xEvent *) &ce); 277} 278 279static Bool 280RRCrtcPendingProperties (RRCrtcPtr crtc) 281{ 282 ScreenPtr pScreen = crtc->pScreen; 283 rrScrPriv(pScreen); 284 int o; 285 286 for (o = 0; o < pScrPriv->numOutputs; o++) 287 { 288 RROutputPtr output = pScrPriv->outputs[o]; 289 if (output->crtc == crtc && output->pendingProperties) 290 return TRUE; 291 } 292 return FALSE; 293} 294 295/* 296 * Request that the Crtc be reconfigured 297 */ 298Bool 299RRCrtcSet (RRCrtcPtr crtc, 300 RRModePtr mode, 301 int x, 302 int y, 303 Rotation rotation, 304 int numOutputs, 305 RROutputPtr *outputs) 306{ 307 ScreenPtr pScreen = crtc->pScreen; 308 Bool ret = FALSE; 309 rrScrPriv(pScreen); 310 311 /* See if nothing changed */ 312 if (crtc->mode == mode && 313 crtc->x == x && 314 crtc->y == y && 315 crtc->rotation == rotation && 316 crtc->numOutputs == numOutputs && 317 !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) && 318 !RRCrtcPendingProperties (crtc) && 319 !RRCrtcPendingTransform (crtc)) 320 { 321 ret = TRUE; 322 } 323 else 324 { 325#if RANDR_12_INTERFACE 326 if (pScrPriv->rrCrtcSet) 327 { 328 ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 329 rotation, numOutputs, outputs); 330 } 331 else 332#endif 333 { 334#if RANDR_10_INTERFACE 335 if (pScrPriv->rrSetConfig) 336 { 337 RRScreenSize size; 338 RRScreenRate rate; 339 340 if (!mode) 341 { 342 RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL); 343 ret = TRUE; 344 } 345 else 346 { 347 size.width = mode->mode.width; 348 size.height = mode->mode.height; 349 if (outputs[0]->mmWidth && outputs[0]->mmHeight) 350 { 351 size.mmWidth = outputs[0]->mmWidth; 352 size.mmHeight = outputs[0]->mmHeight; 353 } 354 else 355 { 356 size.mmWidth = pScreen->mmWidth; 357 size.mmHeight = pScreen->mmHeight; 358 } 359 size.nRates = 1; 360 rate.rate = RRVerticalRefresh (&mode->mode); 361 size.pRates = &rate; 362 ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size); 363 /* 364 * Old 1.0 interface tied screen size to mode size 365 */ 366 if (ret) 367 { 368 RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs); 369 RRScreenSizeNotify (pScreen); 370 } 371 } 372 } 373#endif 374 } 375 if (ret) 376 { 377 int o; 378 RRTellChanged (pScreen); 379 380 for (o = 0; o < numOutputs; o++) 381 RRPostPendingProperties (outputs[o]); 382 } 383 } 384 return ret; 385} 386 387/* 388 * Return crtc transform 389 */ 390RRTransformPtr 391RRCrtcGetTransform (RRCrtcPtr crtc) 392{ 393 RRTransformPtr transform = &crtc->client_pending_transform; 394 395 if (pixman_transform_is_identity (&transform->transform)) 396 return NULL; 397 return transform; 398} 399 400/* 401 * Check whether the pending and current transforms are the same 402 */ 403Bool 404RRCrtcPendingTransform (RRCrtcPtr crtc) 405{ 406 return memcmp (&crtc->client_current_transform.transform, 407 &crtc->client_pending_transform.transform, 408 sizeof (PictTransform)) != 0; 409} 410 411/* 412 * Destroy a Crtc at shutdown 413 */ 414void 415RRCrtcDestroy (RRCrtcPtr crtc) 416{ 417 FreeResource (crtc->id, 0); 418} 419 420static int 421RRCrtcDestroyResource (pointer value, XID pid) 422{ 423 RRCrtcPtr crtc = (RRCrtcPtr) value; 424 ScreenPtr pScreen = crtc->pScreen; 425 426 if (pScreen) 427 { 428 rrScrPriv(pScreen); 429 int i; 430 431 for (i = 0; i < pScrPriv->numCrtcs; i++) 432 { 433 if (pScrPriv->crtcs[i] == crtc) 434 { 435 memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1, 436 (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr)); 437 --pScrPriv->numCrtcs; 438 break; 439 } 440 } 441 } 442 free(crtc->gammaRed); 443 if (crtc->mode) 444 RRModeDestroy (crtc->mode); 445 free(crtc); 446 return 1; 447} 448 449/* 450 * Request that the Crtc gamma be changed 451 */ 452 453Bool 454RRCrtcGammaSet (RRCrtcPtr crtc, 455 CARD16 *red, 456 CARD16 *green, 457 CARD16 *blue) 458{ 459 Bool ret = TRUE; 460#if RANDR_12_INTERFACE 461 ScreenPtr pScreen = crtc->pScreen; 462#endif 463 464 memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16)); 465 memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16)); 466 memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16)); 467#if RANDR_12_INTERFACE 468 if (pScreen) 469 { 470 rrScrPriv(pScreen); 471 if (pScrPriv->rrCrtcSetGamma) 472 ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc); 473 } 474#endif 475 return ret; 476} 477 478/* 479 * Request current gamma back from the DDX (if possible). 480 * This includes gamma size. 481 */ 482Bool 483RRCrtcGammaGet(RRCrtcPtr crtc) 484{ 485 Bool ret = TRUE; 486#if RANDR_12_INTERFACE 487 ScreenPtr pScreen = crtc->pScreen; 488#endif 489 490#if RANDR_12_INTERFACE 491 if (pScreen) 492 { 493 rrScrPriv(pScreen); 494 if (pScrPriv->rrCrtcGetGamma) 495 ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc); 496 } 497#endif 498 return ret; 499} 500 501/* 502 * Notify the extension that the Crtc gamma has been changed 503 * The driver calls this whenever it has changed the gamma values 504 * in the RRCrtcRec 505 */ 506 507Bool 508RRCrtcGammaNotify (RRCrtcPtr crtc) 509{ 510 return TRUE; /* not much going on here */ 511} 512 513static void 514RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform, 515 int *width, int *height) 516{ 517 BoxRec box; 518 519 if (mode == NULL) { 520 *width = 0; 521 *height = 0; 522 return; 523 } 524 525 box.x1 = 0; 526 box.y1 = 0; 527 box.x2 = mode->mode.width; 528 box.y2 = mode->mode.height; 529 530 pixman_transform_bounds (transform, &box); 531 *width = box.x2 - box.x1; 532 *height = box.y2 - box.y1; 533} 534 535/** 536 * Returns the width/height that the crtc scans out from the framebuffer 537 */ 538void 539RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height) 540{ 541 RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height); 542} 543 544/* 545 * Set the size of the gamma table at server startup time 546 */ 547 548Bool 549RRCrtcGammaSetSize (RRCrtcPtr crtc, 550 int size) 551{ 552 CARD16 *gamma; 553 554 if (size == crtc->gammaSize) 555 return TRUE; 556 if (size) 557 { 558 gamma = malloc(size * 3 * sizeof (CARD16)); 559 if (!gamma) 560 return FALSE; 561 } 562 else 563 gamma = NULL; 564 free(crtc->gammaRed); 565 crtc->gammaRed = gamma; 566 crtc->gammaGreen = gamma + size; 567 crtc->gammaBlue = gamma + size*2; 568 crtc->gammaSize = size; 569 return TRUE; 570} 571 572/* 573 * Set the pending CRTC transformation 574 */ 575 576int 577RRCrtcTransformSet (RRCrtcPtr crtc, 578 PictTransformPtr transform, 579 struct pixman_f_transform *f_transform, 580 struct pixman_f_transform *f_inverse, 581 char *filter_name, 582 int filter_len, 583 xFixed *params, 584 int nparams) 585{ 586 PictFilterPtr filter = NULL; 587 int width = 0, height = 0; 588 589 if (!crtc->transforms) 590 return BadValue; 591 592 if (filter_len) 593 { 594 filter = PictureFindFilter (crtc->pScreen, 595 filter_name, 596 filter_len); 597 if (!filter) 598 return BadName; 599 if (filter->ValidateParams) 600 { 601 if (!filter->ValidateParams (crtc->pScreen, filter->id, 602 params, nparams, &width, &height)) 603 return BadMatch; 604 } 605 else { 606 width = filter->width; 607 height = filter->height; 608 } 609 } 610 else 611 { 612 if (nparams) 613 return BadMatch; 614 } 615 if (!RRTransformSetFilter (&crtc->client_pending_transform, 616 filter, params, nparams, width, height)) 617 return BadAlloc; 618 619 crtc->client_pending_transform.transform = *transform; 620 crtc->client_pending_transform.f_transform = *f_transform; 621 crtc->client_pending_transform.f_inverse = *f_inverse; 622 return Success; 623} 624 625/* 626 * Initialize crtc type 627 */ 628Bool 629RRCrtcInit (void) 630{ 631 RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC"); 632 if (!RRCrtcType) 633 return FALSE; 634 635 return TRUE; 636} 637 638/* 639 * Initialize crtc type error value 640 */ 641void 642RRCrtcInitErrorValue(void) 643{ 644 SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc); 645} 646 647int 648ProcRRGetCrtcInfo (ClientPtr client) 649{ 650 REQUEST(xRRGetCrtcInfoReq); 651 xRRGetCrtcInfoReply rep; 652 RRCrtcPtr crtc; 653 CARD8 *extra; 654 unsigned long extraLen; 655 ScreenPtr pScreen; 656 rrScrPrivPtr pScrPriv; 657 RRModePtr mode; 658 RROutput *outputs; 659 RROutput *possible; 660 int i, j, k, n; 661 int width, height; 662 BoxRec panned_area; 663 664 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq); 665 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 666 667 /* All crtcs must be associated with screens before client 668 * requests are processed 669 */ 670 pScreen = crtc->pScreen; 671 pScrPriv = rrGetScrPriv(pScreen); 672 673 mode = crtc->mode; 674 675 rep.type = X_Reply; 676 rep.status = RRSetConfigSuccess; 677 rep.sequenceNumber = client->sequence; 678 rep.length = 0; 679 rep.timestamp = pScrPriv->lastSetTime.milliseconds; 680 if (pScrPriv->rrGetPanning && 681 pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) && 682 (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) 683 { 684 rep.x = panned_area.x1; 685 rep.y = panned_area.y1; 686 rep.width = panned_area.x2 - panned_area.x1; 687 rep.height = panned_area.y2 - panned_area.y1; 688 } 689 else 690 { 691 RRCrtcGetScanoutSize (crtc, &width, &height); 692 rep.x = crtc->x; 693 rep.y = crtc->y; 694 rep.width = width; 695 rep.height = height; 696 } 697 rep.mode = mode ? mode->mode.id : 0; 698 rep.rotation = crtc->rotation; 699 rep.rotations = crtc->rotations; 700 rep.nOutput = crtc->numOutputs; 701 k = 0; 702 for (i = 0; i < pScrPriv->numOutputs; i++) 703 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 704 if (pScrPriv->outputs[i]->crtcs[j] == crtc) 705 k++; 706 rep.nPossibleOutput = k; 707 708 rep.length = rep.nOutput + rep.nPossibleOutput; 709 710 extraLen = rep.length << 2; 711 if (extraLen) 712 { 713 extra = malloc(extraLen); 714 if (!extra) 715 return BadAlloc; 716 } 717 else 718 extra = NULL; 719 720 outputs = (RROutput *) extra; 721 possible = (RROutput *) (outputs + rep.nOutput); 722 723 for (i = 0; i < crtc->numOutputs; i++) 724 { 725 outputs[i] = crtc->outputs[i]->id; 726 if (client->swapped) 727 swapl (&outputs[i], n); 728 } 729 k = 0; 730 for (i = 0; i < pScrPriv->numOutputs; i++) 731 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++) 732 if (pScrPriv->outputs[i]->crtcs[j] == crtc) 733 { 734 possible[k] = pScrPriv->outputs[i]->id; 735 if (client->swapped) 736 swapl (&possible[k], n); 737 k++; 738 } 739 740 if (client->swapped) { 741 swaps(&rep.sequenceNumber, n); 742 swapl(&rep.length, n); 743 swapl(&rep.timestamp, n); 744 swaps(&rep.x, n); 745 swaps(&rep.y, n); 746 swaps(&rep.width, n); 747 swaps(&rep.height, n); 748 swapl(&rep.mode, n); 749 swaps(&rep.rotation, n); 750 swaps(&rep.rotations, n); 751 swaps(&rep.nOutput, n); 752 swaps(&rep.nPossibleOutput, n); 753 } 754 WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep); 755 if (extraLen) 756 { 757 WriteToClient (client, extraLen, (char *) extra); 758 free(extra); 759 } 760 761 return Success; 762} 763 764int 765ProcRRSetCrtcConfig (ClientPtr client) 766{ 767 REQUEST(xRRSetCrtcConfigReq); 768 xRRSetCrtcConfigReply rep; 769 ScreenPtr pScreen; 770 rrScrPrivPtr pScrPriv; 771 RRCrtcPtr crtc; 772 RRModePtr mode; 773 int numOutputs; 774 RROutputPtr *outputs = NULL; 775 RROutput *outputIds; 776 TimeStamp configTime; 777 TimeStamp time; 778 Rotation rotation; 779 int rc, i, j; 780 781 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq); 782 numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq))); 783 784 VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess); 785 786 if (stuff->mode == None) 787 { 788 mode = NULL; 789 if (numOutputs > 0) 790 return BadMatch; 791 } 792 else 793 { 794 VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess); 795 if (numOutputs == 0) 796 return BadMatch; 797 } 798 if (numOutputs) 799 { 800 outputs = malloc(numOutputs * sizeof (RROutputPtr)); 801 if (!outputs) 802 return BadAlloc; 803 } 804 else 805 outputs = NULL; 806 807 outputIds = (RROutput *) (stuff + 1); 808 for (i = 0; i < numOutputs; i++) 809 { 810 rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i], 811 RROutputType, client, DixSetAttrAccess); 812 if (rc != Success) 813 { 814 free(outputs); 815 return rc; 816 } 817 /* validate crtc for this output */ 818 for (j = 0; j < outputs[i]->numCrtcs; j++) 819 if (outputs[i]->crtcs[j] == crtc) 820 break; 821 if (j == outputs[i]->numCrtcs) 822 { 823 free(outputs); 824 return BadMatch; 825 } 826 /* validate mode for this output */ 827 for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) 828 { 829 RRModePtr m = (j < outputs[i]->numModes ? 830 outputs[i]->modes[j] : 831 outputs[i]->userModes[j - outputs[i]->numModes]); 832 if (m == mode) 833 break; 834 } 835 if (j == outputs[i]->numModes + outputs[i]->numUserModes) 836 { 837 free(outputs); 838 return BadMatch; 839 } 840 } 841 /* validate clones */ 842 for (i = 0; i < numOutputs; i++) 843 { 844 for (j = 0; j < numOutputs; j++) 845 { 846 int k; 847 if (i == j) 848 continue; 849 for (k = 0; k < outputs[i]->numClones; k++) 850 { 851 if (outputs[i]->clones[k] == outputs[j]) 852 break; 853 } 854 if (k == outputs[i]->numClones) 855 { 856 free(outputs); 857 return BadMatch; 858 } 859 } 860 } 861 862 pScreen = crtc->pScreen; 863 pScrPriv = rrGetScrPriv(pScreen); 864 865 time = ClientTimeToServerTime(stuff->timestamp); 866 configTime = ClientTimeToServerTime(stuff->configTimestamp); 867 868 if (!pScrPriv) 869 { 870 time = currentTime; 871 rep.status = RRSetConfigFailed; 872 goto sendReply; 873 } 874 875 /* 876 * Validate requested rotation 877 */ 878 rotation = (Rotation) stuff->rotation; 879 880 /* test the rotation bits only! */ 881 switch (rotation & 0xf) { 882 case RR_Rotate_0: 883 case RR_Rotate_90: 884 case RR_Rotate_180: 885 case RR_Rotate_270: 886 break; 887 default: 888 /* 889 * Invalid rotation 890 */ 891 client->errorValue = stuff->rotation; 892 free(outputs); 893 return BadValue; 894 } 895 896 if (mode) 897 { 898 if ((~crtc->rotations) & rotation) 899 { 900 /* 901 * requested rotation or reflection not supported by screen 902 */ 903 client->errorValue = stuff->rotation; 904 free(outputs); 905 return BadMatch; 906 } 907 908#ifdef RANDR_12_INTERFACE 909 /* 910 * Check screen size bounds if the DDX provides a 1.2 interface 911 * for setting screen size. Else, assume the CrtcSet sets 912 * the size along with the mode. If the driver supports transforms, 913 * then it must allow crtcs to display a subset of the screen, so 914 * only do this check for drivers without transform support. 915 */ 916 if (pScrPriv->rrScreenSetSize && !crtc->transforms) 917 { 918 int source_width; 919 int source_height; 920 PictTransform transform; 921 struct pixman_f_transform f_transform, f_inverse; 922 923 RRTransformCompute (stuff->x, stuff->y, 924 mode->mode.width, mode->mode.height, 925 rotation, 926 &crtc->client_pending_transform, 927 &transform, &f_transform, &f_inverse); 928 929 RRModeGetScanoutSize (mode, &transform, &source_width, &source_height); 930 if (stuff->x + source_width > pScreen->width) 931 { 932 client->errorValue = stuff->x; 933 free(outputs); 934 return BadValue; 935 } 936 937 if (stuff->y + source_height > pScreen->height) 938 { 939 client->errorValue = stuff->y; 940 free(outputs); 941 return BadValue; 942 } 943 } 944#endif 945 } 946 947 if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y, 948 rotation, numOutputs, outputs)) 949 { 950 rep.status = RRSetConfigFailed; 951 goto sendReply; 952 } 953 rep.status = RRSetConfigSuccess; 954 pScrPriv->lastSetTime = time; 955 956sendReply: 957 free(outputs); 958 959 rep.type = X_Reply; 960 /* rep.status has already been filled in */ 961 rep.length = 0; 962 rep.sequenceNumber = client->sequence; 963 rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; 964 965 if (client->swapped) 966 { 967 int n; 968 swaps(&rep.sequenceNumber, n); 969 swapl(&rep.length, n); 970 swapl(&rep.newTimestamp, n); 971 } 972 WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep); 973 974 return Success; 975} 976 977int 978ProcRRGetPanning (ClientPtr client) 979{ 980 REQUEST(xRRGetPanningReq); 981 xRRGetPanningReply rep; 982 RRCrtcPtr crtc; 983 ScreenPtr pScreen; 984 rrScrPrivPtr pScrPriv; 985 BoxRec total; 986 BoxRec tracking; 987 INT16 border[4]; 988 int n; 989 990 REQUEST_SIZE_MATCH(xRRGetPanningReq); 991 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 992 993 /* All crtcs must be associated with screens before client 994 * requests are processed 995 */ 996 pScreen = crtc->pScreen; 997 pScrPriv = rrGetScrPriv(pScreen); 998 999 if (!pScrPriv) 1000 return RRErrorBase + BadRRCrtc; 1001 1002 memset(&rep, 0, sizeof(rep)); 1003 rep.type = X_Reply; 1004 rep.status = RRSetConfigSuccess; 1005 rep.sequenceNumber = client->sequence; 1006 rep.length = 1; 1007 rep.timestamp = pScrPriv->lastSetTime.milliseconds; 1008 1009 if (pScrPriv->rrGetPanning && 1010 pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) { 1011 rep.left = total.x1; 1012 rep.top = total.y1; 1013 rep.width = total.x2 - total.x1; 1014 rep.height = total.y2 - total.y1; 1015 rep.track_left = tracking.x1; 1016 rep.track_top = tracking.y1; 1017 rep.track_width = tracking.x2 - tracking.x1; 1018 rep.track_height = tracking.y2 - tracking.y1; 1019 rep.border_left = border[0]; 1020 rep.border_top = border[1]; 1021 rep.border_right = border[2]; 1022 rep.border_bottom = border[3]; 1023 } 1024 1025 if (client->swapped) { 1026 swaps(&rep.sequenceNumber, n); 1027 swapl(&rep.length, n); 1028 swaps(&rep.timestamp, n); 1029 swaps(&rep.left, n); 1030 swaps(&rep.top, n); 1031 swaps(&rep.width, n); 1032 swaps(&rep.height, n); 1033 swaps(&rep.track_left, n); 1034 swaps(&rep.track_top, n); 1035 swaps(&rep.track_width, n); 1036 swaps(&rep.track_height, n); 1037 swaps(&rep.border_left, n); 1038 swaps(&rep.border_top, n); 1039 swaps(&rep.border_right, n); 1040 swaps(&rep.border_bottom, n); 1041 } 1042 WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep); 1043 return Success; 1044} 1045 1046int 1047ProcRRSetPanning (ClientPtr client) 1048{ 1049 REQUEST(xRRSetPanningReq); 1050 xRRSetPanningReply rep; 1051 RRCrtcPtr crtc; 1052 ScreenPtr pScreen; 1053 rrScrPrivPtr pScrPriv; 1054 TimeStamp time; 1055 BoxRec total; 1056 BoxRec tracking; 1057 INT16 border[4]; 1058 int n; 1059 1060 REQUEST_SIZE_MATCH(xRRSetPanningReq); 1061 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1062 1063 /* All crtcs must be associated with screens before client 1064 * requests are processed 1065 */ 1066 pScreen = crtc->pScreen; 1067 pScrPriv = rrGetScrPriv(pScreen); 1068 1069 if (!pScrPriv) { 1070 time = currentTime; 1071 rep.status = RRSetConfigFailed; 1072 goto sendReply; 1073 } 1074 1075 time = ClientTimeToServerTime(stuff->timestamp); 1076 1077 if (!pScrPriv->rrGetPanning) 1078 return RRErrorBase + BadRRCrtc; 1079 1080 total.x1 = stuff->left; 1081 total.y1 = stuff->top; 1082 total.x2 = total.x1 + stuff->width; 1083 total.y2 = total.y1 + stuff->height; 1084 tracking.x1 = stuff->track_left; 1085 tracking.y1 = stuff->track_top; 1086 tracking.x2 = tracking.x1 + stuff->track_width; 1087 tracking.y2 = tracking.y1 + stuff->track_height; 1088 border[0] = stuff->border_left; 1089 border[1] = stuff->border_top; 1090 border[2] = stuff->border_right; 1091 border[3] = stuff->border_bottom; 1092 1093 if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border)) 1094 return BadMatch; 1095 1096 pScrPriv->lastSetTime = time; 1097 1098 rep.status = RRSetConfigSuccess; 1099 1100sendReply: 1101 rep.type = X_Reply; 1102 rep.sequenceNumber = client->sequence; 1103 rep.length = 0; 1104 rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; 1105 1106 if (client->swapped) { 1107 swaps(&rep.sequenceNumber, n); 1108 swapl(&rep.length, n); 1109 swaps(&rep.newTimestamp, n); 1110 } 1111 WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep); 1112 return Success; 1113} 1114 1115int 1116ProcRRGetCrtcGammaSize (ClientPtr client) 1117{ 1118 REQUEST(xRRGetCrtcGammaSizeReq); 1119 xRRGetCrtcGammaSizeReply reply; 1120 RRCrtcPtr crtc; 1121 int n; 1122 1123 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq); 1124 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1125 1126 /* Gamma retrieval failed, any better error? */ 1127 if (!RRCrtcGammaGet(crtc)) 1128 return RRErrorBase + BadRRCrtc; 1129 1130 reply.type = X_Reply; 1131 reply.sequenceNumber = client->sequence; 1132 reply.length = 0; 1133 reply.size = crtc->gammaSize; 1134 if (client->swapped) { 1135 swaps (&reply.sequenceNumber, n); 1136 swapl (&reply.length, n); 1137 swaps (&reply.size, n); 1138 } 1139 WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply); 1140 return Success; 1141} 1142 1143int 1144ProcRRGetCrtcGamma (ClientPtr client) 1145{ 1146 REQUEST(xRRGetCrtcGammaReq); 1147 xRRGetCrtcGammaReply reply; 1148 RRCrtcPtr crtc; 1149 int n; 1150 unsigned long len; 1151 char *extra = NULL; 1152 1153 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq); 1154 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1155 1156 /* Gamma retrieval failed, any better error? */ 1157 if (!RRCrtcGammaGet(crtc)) 1158 return RRErrorBase + BadRRCrtc; 1159 1160 len = crtc->gammaSize * 3 * 2; 1161 1162 if (crtc->gammaSize) { 1163 extra = malloc(len); 1164 if (!extra) 1165 return BadAlloc; 1166 } 1167 1168 reply.type = X_Reply; 1169 reply.sequenceNumber = client->sequence; 1170 reply.length = bytes_to_int32(len); 1171 reply.size = crtc->gammaSize; 1172 if (client->swapped) { 1173 swaps (&reply.sequenceNumber, n); 1174 swapl (&reply.length, n); 1175 swaps (&reply.size, n); 1176 } 1177 WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply); 1178 if (crtc->gammaSize) 1179 { 1180 memcpy(extra, crtc->gammaRed, len); 1181 client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; 1182 WriteSwappedDataToClient (client, len, extra); 1183 free(extra); 1184 } 1185 return Success; 1186} 1187 1188int 1189ProcRRSetCrtcGamma (ClientPtr client) 1190{ 1191 REQUEST(xRRSetCrtcGammaReq); 1192 RRCrtcPtr crtc; 1193 unsigned long len; 1194 CARD16 *red, *green, *blue; 1195 1196 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq); 1197 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1198 1199 len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq)); 1200 if (len < (stuff->size * 3 + 1) >> 1) 1201 return BadLength; 1202 1203 if (stuff->size != crtc->gammaSize) 1204 return BadMatch; 1205 1206 red = (CARD16 *) (stuff + 1); 1207 green = red + crtc->gammaSize; 1208 blue = green + crtc->gammaSize; 1209 1210 RRCrtcGammaSet (crtc, red, green, blue); 1211 1212 return Success; 1213} 1214 1215/* Version 1.3 additions */ 1216 1217int 1218ProcRRSetCrtcTransform (ClientPtr client) 1219{ 1220 REQUEST(xRRSetCrtcTransformReq); 1221 RRCrtcPtr crtc; 1222 PictTransform transform; 1223 struct pixman_f_transform f_transform, f_inverse; 1224 char *filter; 1225 int nbytes; 1226 xFixed *params; 1227 int nparams; 1228 1229 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq); 1230 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1231 1232 PictTransform_from_xRenderTransform (&transform, &stuff->transform); 1233 pixman_f_transform_from_pixman_transform (&f_transform, &transform); 1234 if (!pixman_f_transform_invert (&f_inverse, &f_transform)) 1235 return BadMatch; 1236 1237 filter = (char *) (stuff + 1); 1238 nbytes = stuff->nbytesFilter; 1239 params = (xFixed *) (filter + pad_to_int32(nbytes)); 1240 nparams = ((xFixed *) stuff + client->req_len) - params; 1241 if (nparams < 0) 1242 return BadLength; 1243 1244 return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse, 1245 filter, nbytes, params, nparams); 1246} 1247 1248 1249#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 1250 1251static int 1252transform_filter_length (RRTransformPtr transform) 1253{ 1254 int nbytes, nparams; 1255 1256 if (transform->filter == NULL) 1257 return 0; 1258 nbytes = strlen (transform->filter->name); 1259 nparams = transform->nparams; 1260 return pad_to_int32(nbytes) + (nparams * sizeof (xFixed)); 1261} 1262 1263static int 1264transform_filter_encode (ClientPtr client, char *output, 1265 CARD16 *nbytesFilter, 1266 CARD16 *nparamsFilter, 1267 RRTransformPtr transform) 1268{ 1269 int nbytes, nparams; 1270 int n; 1271 1272 if (transform->filter == NULL) { 1273 *nbytesFilter = 0; 1274 *nparamsFilter = 0; 1275 return 0; 1276 } 1277 nbytes = strlen (transform->filter->name); 1278 nparams = transform->nparams; 1279 *nbytesFilter = nbytes; 1280 *nparamsFilter = nparams; 1281 memcpy (output, transform->filter->name, nbytes); 1282 while ((nbytes & 3) != 0) 1283 output[nbytes++] = 0; 1284 memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed)); 1285 if (client->swapped) { 1286 swaps (nbytesFilter, n); 1287 swaps (nparamsFilter, n); 1288 SwapLongs ((CARD32 *) (output + nbytes), nparams); 1289 } 1290 nbytes += nparams * sizeof (xFixed); 1291 return nbytes; 1292} 1293 1294static void 1295transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict) 1296{ 1297 xRenderTransform_from_PictTransform (wire, pict); 1298 if (client->swapped) 1299 SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform))); 1300} 1301 1302int 1303ProcRRGetCrtcTransform (ClientPtr client) 1304{ 1305 REQUEST(xRRGetCrtcTransformReq); 1306 xRRGetCrtcTransformReply *reply; 1307 RRCrtcPtr crtc; 1308 int n, nextra; 1309 RRTransformPtr current, pending; 1310 char *extra; 1311 1312 REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq); 1313 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess); 1314 1315 pending = &crtc->client_pending_transform; 1316 current = &crtc->client_current_transform; 1317 1318 nextra = (transform_filter_length (pending) + 1319 transform_filter_length (current)); 1320 1321 reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra); 1322 if (!reply) 1323 return BadAlloc; 1324 1325 extra = (char *) (reply + 1); 1326 reply->type = X_Reply; 1327 reply->sequenceNumber = client->sequence; 1328 reply->length = bytes_to_int32(CrtcTransformExtra + nextra); 1329 1330 reply->hasTransforms = crtc->transforms; 1331 1332 transform_encode (client, &reply->pendingTransform, &pending->transform); 1333 extra += transform_filter_encode (client, extra, 1334 &reply->pendingNbytesFilter, 1335 &reply->pendingNparamsFilter, 1336 pending); 1337 1338 transform_encode (client, &reply->currentTransform, ¤t->transform); 1339 extra += transform_filter_encode (client, extra, 1340 &reply->currentNbytesFilter, 1341 &reply->currentNparamsFilter, 1342 current); 1343 1344 if (client->swapped) { 1345 swaps (&reply->sequenceNumber, n); 1346 swapl (&reply->length, n); 1347 } 1348 WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply); 1349 free(reply); 1350 return Success; 1351} 1352