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