1/* 2 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 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#ifdef HAVE_XORG_CONFIG_H 24#include <xorg-config.h> 25#else 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif 29#endif 30 31#include "xf86.h" 32#include "os.h" 33#include "globals.h" 34#include "xf86.h" 35#include "xf86Modes.h" 36#include "xf86Priv.h" 37#include "xf86DDC.h" 38#include "mipointer.h" 39#include "windowstr.h" 40#include "inputstr.h" 41#include <randrstr.h> 42#include <X11/extensions/render.h> 43 44#include "xf86Crtc.h" 45#include "xf86RandR12.h" 46 47typedef struct _xf86RandR12Info { 48 int virtualX; 49 int virtualY; 50 int mmWidth; 51 int mmHeight; 52 int maxX; 53 int maxY; 54 int pointerX; 55 int pointerY; 56 Rotation rotation; /* current mode */ 57 Rotation supported_rotations; /* driver supported */ 58 59 /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends 60 * (actually, any time that we switch back into our VT). 61 * 62 * See https://bugs.freedesktop.org/show_bug.cgi?id=21554 63 */ 64 xf86EnterVTProc *orig_EnterVT; 65} XF86RandRInfoRec, *XF86RandRInfoPtr; 66 67#ifdef RANDR_12_INTERFACE 68static Bool xf86RandR12Init12 (ScreenPtr pScreen); 69static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); 70#endif 71 72static int xf86RandR12Generation; 73 74static DevPrivateKeyRec xf86RandR12KeyRec; 75static DevPrivateKey xf86RandR12Key; 76#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \ 77 dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key)) 78 79 80static int 81xf86RandR12ModeRefresh (DisplayModePtr mode) 82{ 83 if (mode->VRefresh) 84 return (int) (mode->VRefresh + 0.5); 85 else 86 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); 87} 88 89/* Adapt panning area; return TRUE if panning area was valid without adaption */ 90static int 91xf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight) 92{ 93 int ret = TRUE; 94 95 if (crtc->version < 2) 96 return FALSE; 97 98 if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) { 99 /* Panning in X is disabled */ 100 if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2) 101 /* Illegal configuration -> fail/disable */ 102 ret = FALSE; 103 crtc->panningTotalArea.x1 = crtc->panningTotalArea.x2 = 0; 104 crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0; 105 crtc->panningBorder[0] = crtc->panningBorder[2] = 0; 106 } else { 107 /* Panning in X is enabled */ 108 if (crtc->panningTotalArea.x1 < 0) { 109 /* Panning region outside screen -> move inside */ 110 crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1; 111 crtc->panningTotalArea.x1 = 0; 112 ret = FALSE; 113 } 114 if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) { 115 /* Panning region smaller than displayed area -> crop to displayed area */ 116 crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay; 117 ret = FALSE; 118 } 119 if (crtc->panningTotalArea.x2 > screenWidth) { 120 /* Panning region larger than screen -> move inside, then crop to screen */ 121 crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth; 122 crtc->panningTotalArea.x2 = screenWidth; 123 ret = FALSE; 124 if (crtc->panningTotalArea.x1 < 0) 125 crtc->panningTotalArea.x1 = 0; 126 } 127 if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) { 128 /* Borders too large -> set to 0 */ 129 crtc->panningBorder[0] = crtc->panningBorder[2] = 0; 130 ret = FALSE; 131 } 132 } 133 134 if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) { 135 /* Panning in Y is disabled */ 136 if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2) 137 /* Illegal configuration -> fail/disable */ 138 ret = FALSE; 139 crtc->panningTotalArea.y1 = crtc->panningTotalArea.y2 = 0; 140 crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0; 141 crtc->panningBorder[1] = crtc->panningBorder[3] = 0; 142 } else { 143 /* Panning in Y is enabled */ 144 if (crtc->panningTotalArea.y1 < 0) { 145 /* Panning region outside screen -> move inside */ 146 crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1; 147 crtc->panningTotalArea.y1 = 0; 148 ret = FALSE; 149 } 150 if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) { 151 /* Panning region smaller than displayed area -> crop to displayed area */ 152 crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay; 153 ret = FALSE; 154 } 155 if (crtc->panningTotalArea.y2 > screenHeight) { 156 /* Panning region larger than screen -> move inside, then crop to screen */ 157 crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight; 158 crtc->panningTotalArea.y2 = screenHeight; 159 ret = FALSE; 160 if (crtc->panningTotalArea.y1 < 0) 161 crtc->panningTotalArea.y1 = 0; 162 } 163 if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) { 164 /* Borders too large -> set to 0 */ 165 crtc->panningBorder[1] = crtc->panningBorder[3] = 0; 166 ret = FALSE; 167 } 168 } 169 170 return ret; 171} 172 173/* 174 * The heart of the panning operation: 175 * 176 * Given a frame buffer position (fb_x, fb_y), 177 * and a crtc position (crtc_x, crtc_y), 178 * and a transform matrix which maps frame buffer to crtc, 179 * compute a panning position (pan_x, pan_y) that 180 * makes the resulting transform line those two up 181 */ 182 183static void 184xf86ComputeCrtcPan (Bool transform_in_use, 185 struct pixman_f_transform *m, 186 double screen_x, double screen_y, 187 double crtc_x, double crtc_y, 188 int old_pan_x, int old_pan_y, 189 int *new_pan_x, int *new_pan_y) 190{ 191 if (transform_in_use) { 192 /* 193 * Given the current transform, M, the current position 194 * on the Screen, S, and the desired position on the CRTC, 195 * C, compute a translation, T, such that: 196 * 197 * M T S = C 198 * 199 * where T is of the form 200 * 201 * | 1 0 dx | 202 * | 0 1 dy | 203 * | 0 0 1 | 204 * 205 * M T S = 206 * | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 | | Cx F | 207 * | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F | 208 * | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 | | F | 209 * 210 * R = M S 211 * 212 * Cx F = M00 dx + M01 dy + R0 213 * Cy F = M10 dx + M11 dy + R1 214 * F = M20 dx + M21 dy + R2 215 * 216 * Zero out dx, then dy 217 * 218 * F (Cx M10 - Cy M00) = 219 * (M10 M01 - M00 M11) dy + M10 R0 - M00 R1 220 * F (M10 - Cy M20) = 221 * (M10 M21 - M20 M11) dy + M10 R2 - M20 R1 222 * 223 * F (Cx M11 - Cy M01) = 224 * (M11 M00 - M01 M10) dx + M11 R0 - M01 R1 225 * F (M11 - Cy M21) = 226 * (M11 M20 - M21 M10) dx + M11 R2 - M21 R1 227 * 228 * Make some temporaries 229 * 230 * T = | Cx M10 - Cy M00 | 231 * | Cx M11 - Cy M01 | 232 * 233 * U = | M10 M01 - M00 M11 | 234 * | M11 M00 - M01 M10 | 235 * 236 * Q = | M10 R0 - M00 R1 | 237 * | M11 R0 - M01 R1 | 238 * 239 * P = | M10 - Cy M20 | 240 * | M11 - Cy M21 | 241 * 242 * W = | M10 M21 - M20 M11 | 243 * | M11 M20 - M21 M10 | 244 * 245 * V = | M10 R2 - M20 R1 | 246 * | M11 R2 - M21 R1 | 247 * 248 * Rewrite: 249 * 250 * F T0 = U0 dy + Q0 251 * F P0 = W0 dy + V0 252 * F T1 = U1 dx + Q1 253 * F P1 = W1 dx + V1 254 * 255 * Solve for F (two ways) 256 * 257 * F (W0 T0 - U0 P0) = W0 Q0 - U0 V0 258 * 259 * W0 Q0 - U0 V0 260 * F = ------------- 261 * W0 T0 - U0 P0 262 * 263 * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1 264 * 265 * W1 Q1 - U1 V1 266 * F = ------------- 267 * W1 T1 - U1 P1 268 * 269 * We'll use which ever solution works (denominator != 0) 270 * 271 * Finally, solve for dx and dy: 272 * 273 * dx = (F T1 - Q1) / U1 274 * dx = (F P1 - V1) / W1 275 * 276 * dy = (F T0 - Q0) / U0 277 * dy = (F P0 - V0) / W0 278 */ 279 double r[3]; 280 double q[2], u[2], t[2], v[2], w[2], p[2]; 281 double f; 282 struct pict_f_vector d; 283 int i; 284 285 /* Get the un-normalized crtc coordinates again */ 286 for (i = 0; i < 3; i++) 287 r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2]; 288 289 /* Combine values into temporaries */ 290 for (i = 0; i < 2; i++) { 291 q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1]; 292 u[i] = m->m[1][i] * m->m[0][1-i] - m->m[0][i] * m->m[1][1-i]; 293 t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y; 294 295 v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1]; 296 w[i] = m->m[1][i] * m->m[2][1-i] - m->m[2][i] * m->m[1][1-i]; 297 p[i] = m->m[1][i] - m->m[2][i] * crtc_y; 298 } 299 300 /* Find a way to compute f */ 301 f = 0; 302 for (i = 0; i < 2; i++) { 303 double a = w[i] * q[i] - u[i] * v[i]; 304 double b = w[i] * t[i] - u[i] * p[i]; 305 if (b != 0) { 306 f = a/b; 307 break; 308 } 309 } 310 311 /* Solve for the resulting transform vector */ 312 for (i = 0; i < 2; i++) { 313 if (u[i]) 314 d.v[1-i] = (t[i] * f - q[i]) / u[i]; 315 else if (w[1]) 316 d.v[1-i] = (p[i] * f - v[i]) / w[i]; 317 else 318 d.v[1-i] = 0; 319 } 320 *new_pan_x = old_pan_x - floor (d.v[0] + 0.5); 321 *new_pan_y = old_pan_y - floor (d.v[1] + 0.5); 322 } else { 323 *new_pan_x = screen_x - crtc_x; 324 *new_pan_y = screen_y - crtc_y; 325 } 326} 327 328static void 329xf86RandR13Pan (xf86CrtcPtr crtc, int x, int y) 330{ 331 int newX, newY; 332 int width, height; 333 Bool panned = FALSE; 334 335 if (crtc->version < 2) 336 return; 337 338 if (! crtc->enabled || 339 (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 && 340 crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1)) 341 return; 342 343 newX = crtc->x; 344 newY = crtc->y; 345 width = crtc->mode.HDisplay; 346 height = crtc->mode.VDisplay; 347 348 if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 || 349 (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) && 350 (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 || 351 (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2))) 352 { 353 struct pict_f_vector c; 354 355 /* 356 * Pre-clip the mouse position to the panning area so that we don't 357 * push the crtc outside. This doesn't deal with changes to the 358 * panning values, only mouse position changes. 359 */ 360 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) 361 { 362 if (x < crtc->panningTotalArea.x1) 363 x = crtc->panningTotalArea.x1; 364 if (x >= crtc->panningTotalArea.x2) 365 x = crtc->panningTotalArea.x2 - 1; 366 } 367 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) 368 { 369 if (y < crtc->panningTotalArea.y1) 370 y = crtc->panningTotalArea.y1; 371 if (y >= crtc->panningTotalArea.y2) 372 y = crtc->panningTotalArea.y2 - 1; 373 } 374 375 c.v[0] = x; 376 c.v[1] = y; 377 c.v[2] = 1.0; 378 if (crtc->transform_in_use) { 379 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c); 380 } else { 381 c.v[0] -= crtc->x; 382 c.v[1] -= crtc->y; 383 } 384 385 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { 386 if (c.v[0] < crtc->panningBorder[0]) { 387 c.v[0] = crtc->panningBorder[0]; 388 panned = TRUE; 389 } 390 if (c.v[0] >= width - crtc->panningBorder[2]) { 391 c.v[0] = width - crtc->panningBorder[2] - 1; 392 panned = TRUE; 393 } 394 } 395 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 396 if (c.v[1] < crtc->panningBorder[1]) { 397 c.v[1] = crtc->panningBorder[1]; 398 panned = TRUE; 399 } 400 if (c.v[1] >= height - crtc->panningBorder[3]) { 401 c.v[1] = height - crtc->panningBorder[3] - 1; 402 panned = TRUE; 403 } 404 } 405 if (panned) 406 xf86ComputeCrtcPan (crtc->transform_in_use, 407 &crtc->f_framebuffer_to_crtc, 408 x, y, c.v[0], c.v[1], 409 newX, newY, &newX, &newY); 410 } 411 412 /* 413 * Ensure that the crtc is within the panning region. 414 * 415 * XXX This computation only works when we do not have a transform 416 * in use. 417 */ 418 if (!crtc->transform_in_use) 419 { 420 /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */ 421 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { 422 if (newX > crtc->panningTotalArea.x2 - width) 423 newX = crtc->panningTotalArea.x2 - width; 424 if (newX < crtc->panningTotalArea.x1) 425 newX = crtc->panningTotalArea.x1; 426 } 427 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 428 if (newY > crtc->panningTotalArea.y2 - height) 429 newY = crtc->panningTotalArea.y2 - height; 430 if (newY < crtc->panningTotalArea.y1) 431 newY = crtc->panningTotalArea.y1; 432 } 433 } 434 if (newX != crtc->x || newY != crtc->y) 435 xf86CrtcSetOrigin (crtc, newX, newY); 436} 437 438static Bool 439xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) 440{ 441 RRScreenSizePtr pSize; 442 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 443 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 444 DisplayModePtr mode; 445 int refresh0 = 60; 446 int maxX = 0, maxY = 0; 447 448 *rotations = randrp->supported_rotations; 449 450 if (randrp->virtualX == -1 || randrp->virtualY == -1) 451 { 452 randrp->virtualX = scrp->virtualX; 453 randrp->virtualY = scrp->virtualY; 454 } 455 456 /* Re-probe the outputs for new monitors or modes */ 457 if (scrp->vtSema) 458 { 459 xf86ProbeOutputModes (scrp, 0, 0); 460 xf86SetScrnInfoModes (scrp); 461 } 462 463 for (mode = scrp->modes; ; mode = mode->next) 464 { 465 int refresh = xf86RandR12ModeRefresh (mode); 466 if (randrp->maxX == 0 || randrp->maxY == 0) 467 { 468 if (maxX < mode->HDisplay) 469 maxX = mode->HDisplay; 470 if (maxY < mode->VDisplay) 471 maxY = mode->VDisplay; 472 } 473 if (mode == scrp->modes) 474 refresh0 = refresh; 475 pSize = RRRegisterSize (pScreen, 476 mode->HDisplay, mode->VDisplay, 477 randrp->mmWidth, randrp->mmHeight); 478 if (!pSize) 479 return FALSE; 480 RRRegisterRate (pScreen, pSize, refresh); 481 482 if (xf86ModesEqual(mode, scrp->currentMode)) 483 { 484 RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); 485 } 486 if (mode->next == scrp->modes) 487 break; 488 } 489 490 if (randrp->maxX == 0 || randrp->maxY == 0) 491 { 492 randrp->maxX = maxX; 493 randrp->maxY = maxY; 494 } 495 496 return TRUE; 497} 498 499static Bool 500xf86RandR12SetMode (ScreenPtr pScreen, 501 DisplayModePtr mode, 502 Bool useVirtual, 503 int mmWidth, 504 int mmHeight) 505{ 506 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 507 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 508 int oldWidth = pScreen->width; 509 int oldHeight = pScreen->height; 510 int oldmmWidth = pScreen->mmWidth; 511 int oldmmHeight = pScreen->mmHeight; 512 WindowPtr pRoot = pScreen->root; 513 DisplayModePtr currentMode = NULL; 514 Bool ret = TRUE; 515 516 if (pRoot) 517 (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); 518 if (useVirtual) 519 { 520 scrp->virtualX = randrp->virtualX; 521 scrp->virtualY = randrp->virtualY; 522 } 523 else 524 { 525 scrp->virtualX = mode->HDisplay; 526 scrp->virtualY = mode->VDisplay; 527 } 528 529 if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) 530 { 531 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ 532 pScreen->width = scrp->virtualY; 533 pScreen->height = scrp->virtualX; 534 pScreen->mmWidth = mmHeight; 535 pScreen->mmHeight = mmWidth; 536 } 537 else 538 { 539 pScreen->width = scrp->virtualX; 540 pScreen->height = scrp->virtualY; 541 pScreen->mmWidth = mmWidth; 542 pScreen->mmHeight = mmHeight; 543 } 544 if (scrp->currentMode == mode) { 545 /* Save current mode */ 546 currentMode = scrp->currentMode; 547 /* Reset, just so we ensure the drivers SwitchMode is called */ 548 scrp->currentMode = NULL; 549 } 550 /* 551 * We know that if the driver failed to SwitchMode to the rotated 552 * version, then it should revert back to it's prior mode. 553 */ 554 if (!xf86SwitchMode (pScreen, mode)) 555 { 556 ret = FALSE; 557 scrp->virtualX = pScreen->width = oldWidth; 558 scrp->virtualY = pScreen->height = oldHeight; 559 pScreen->mmWidth = oldmmWidth; 560 pScreen->mmHeight = oldmmHeight; 561 scrp->currentMode = currentMode; 562 } 563 564 /* 565 * Make sure the layout is correct 566 */ 567 xf86ReconfigureLayout(); 568 569 /* 570 * Make sure the whole screen is visible 571 */ 572 xf86SetViewport (pScreen, pScreen->width, pScreen->height); 573 xf86SetViewport (pScreen, 0, 0); 574 if (pRoot) 575 (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); 576 return ret; 577} 578 579Bool 580xf86RandR12SetConfig (ScreenPtr pScreen, 581 Rotation rotation, 582 int rate, 583 RRScreenSizePtr pSize) 584{ 585 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); 586 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 587 DisplayModePtr mode; 588 int px, py; 589 Bool useVirtual = FALSE; 590 int maxX = 0, maxY = 0; 591 Rotation oldRotation = randrp->rotation; 592 593 randrp->rotation = rotation; 594 595 if (randrp->virtualX == -1 || randrp->virtualY == -1) 596 { 597 randrp->virtualX = scrp->virtualX; 598 randrp->virtualY = scrp->virtualY; 599 } 600 601 miPointerGetPosition (inputInfo.pointer, &px, &py); 602 for (mode = scrp->modes; ; mode = mode->next) 603 { 604 if (randrp->maxX == 0 || randrp->maxY == 0) 605 { 606 if (maxX < mode->HDisplay) 607 maxX = mode->HDisplay; 608 if (maxY < mode->VDisplay) 609 maxY = mode->VDisplay; 610 } 611 if (mode->HDisplay == pSize->width && 612 mode->VDisplay == pSize->height && 613 (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) 614 break; 615 if (mode->next == scrp->modes) 616 { 617 if (pSize->width == randrp->virtualX && 618 pSize->height == randrp->virtualY) 619 { 620 mode = scrp->modes; 621 useVirtual = TRUE; 622 break; 623 } 624 if (randrp->maxX == 0 || randrp->maxY == 0) 625 { 626 randrp->maxX = maxX; 627 randrp->maxY = maxY; 628 } 629 return FALSE; 630 } 631 } 632 633 if (randrp->maxX == 0 || randrp->maxY == 0) 634 { 635 randrp->maxX = maxX; 636 randrp->maxY = maxY; 637 } 638 639 if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, 640 pSize->mmHeight)) { 641 randrp->rotation = oldRotation; 642 return FALSE; 643 } 644 645 /* 646 * Move the cursor back where it belongs; SwitchMode repositions it 647 */ 648 if (pScreen == miPointerGetScreen(inputInfo.pointer)) 649 { 650 px = (px >= pScreen->width ? (pScreen->width - 1) : px); 651 py = (py >= pScreen->height ? (pScreen->height - 1) : py); 652 653 xf86SetViewport(pScreen, px, py); 654 655 (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE); 656 } 657 658 return TRUE; 659} 660 661static Bool 662xf86RandR12ScreenSetSize (ScreenPtr pScreen, 663 CARD16 width, 664 CARD16 height, 665 CARD32 mmWidth, 666 CARD32 mmHeight) 667{ 668 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 669 ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); 670 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 671 WindowPtr pRoot = pScreen->root; 672 PixmapPtr pScrnPix; 673 Bool ret = FALSE; 674 int c; 675 676 if (xf86RandR12Key) { 677 if (randrp->virtualX == -1 || randrp->virtualY == -1) 678 { 679 randrp->virtualX = pScrn->virtualX; 680 randrp->virtualY = pScrn->virtualY; 681 } 682 } 683 if (pRoot && pScrn->vtSema) 684 (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); 685 686 /* Let the driver update virtualX and virtualY */ 687 if (!(*config->funcs->resize)(pScrn, width, height)) 688 goto finish; 689 690 ret = TRUE; 691 /* Update panning information */ 692 for (c = 0; c < config->num_crtc; c++) { 693 xf86CrtcPtr crtc = config->crtc[c]; 694 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 || 695 crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 696 if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1) 697 crtc->panningTotalArea.x2 += width - pScreen->width; 698 if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1) 699 crtc->panningTotalArea.y2 += height - pScreen->height; 700 if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1) 701 crtc->panningTrackingArea.x2 += width - pScreen->width; 702 if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1) 703 crtc->panningTrackingArea.y2 += height - pScreen->height; 704 xf86RandR13VerifyPanningArea (crtc, width, height); 705 xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); 706 } 707 } 708 709 pScrnPix = (*pScreen->GetScreenPixmap)(pScreen); 710 pScreen->width = pScrnPix->drawable.width = width; 711 pScreen->height = pScrnPix->drawable.height = height; 712 randrp->mmWidth = pScreen->mmWidth = mmWidth; 713 randrp->mmHeight = pScreen->mmHeight = mmHeight; 714 715 xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1); 716 xf86SetViewport (pScreen, 0, 0); 717 718finish: 719 if (pRoot && pScrn->vtSema) 720 (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); 721#if RANDR_12_INTERFACE 722 if (xf86RandR12Key && pScreen->root && ret) 723 RRScreenSizeNotify (pScreen); 724#endif 725 return ret; 726} 727 728Rotation 729xf86RandR12GetRotation(ScreenPtr pScreen) 730{ 731 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 732 733 return randrp->rotation; 734} 735 736Bool 737xf86RandR12CreateScreenResources (ScreenPtr pScreen) 738{ 739 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 740 xf86CrtcConfigPtr config; 741 XF86RandRInfoPtr randrp; 742 int c; 743 int width, height; 744 int mmWidth, mmHeight; 745#ifdef PANORAMIX 746 /* XXX disable RandR when using Xinerama */ 747 if (!noPanoramiXExtension) 748 return TRUE; 749#endif 750 751 config = XF86_CRTC_CONFIG_PTR(pScrn); 752 randrp = XF86RANDRINFO(pScreen); 753 /* 754 * Compute size of screen 755 */ 756 width = 0; height = 0; 757 for (c = 0; c < config->num_crtc; c++) 758 { 759 xf86CrtcPtr crtc = config->crtc[c]; 760 int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); 761 int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); 762 763 if (crtc->enabled) { 764 if (crtc_width > width) 765 width = crtc_width; 766 if (crtc_height > height) 767 height = crtc_height; 768 if (crtc->panningTotalArea.x2 > width) 769 width = crtc->panningTotalArea.x2; 770 if (crtc->panningTotalArea.y2 > height) 771 height = crtc->panningTotalArea.y2; 772 } 773 } 774 775 if (width && height) 776 { 777 /* 778 * Compute physical size of screen 779 */ 780 if (monitorResolution) 781 { 782 mmWidth = width * 25.4 / monitorResolution; 783 mmHeight = height * 25.4 / monitorResolution; 784 } 785 else 786 { 787 xf86OutputPtr output = xf86CompatOutput(pScrn); 788 789 if (output && 790 output->conf_monitor && 791 (output->conf_monitor->mon_width > 0 && 792 output->conf_monitor->mon_height > 0)) 793 { 794 /* 795 * Prefer user configured DisplaySize 796 */ 797 mmWidth = output->conf_monitor->mon_width; 798 mmHeight = output->conf_monitor->mon_height; 799 } 800 else 801 { 802 /* 803 * Otherwise, just set the screen to DEFAULT_DPI 804 */ 805 mmWidth = width * 25.4 / DEFAULT_DPI; 806 mmHeight = height * 25.4 / DEFAULT_DPI; 807 } 808 } 809 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 810 "Setting screen physical size to %d x %d\n", 811 mmWidth, mmHeight); 812 /* 813 * This is the initial setting of the screen size. 814 * We have to pre-set it here, otherwise panning would be adapted 815 * to the new screen size. 816 */ 817 pScreen->width = width; 818 pScreen->height = height; 819 xf86RandR12ScreenSetSize (pScreen, 820 width, 821 height, 822 mmWidth, 823 mmHeight); 824 } 825 826 if (xf86RandR12Key == NULL) 827 return TRUE; 828 829 if (randrp->virtualX == -1 || randrp->virtualY == -1) 830 { 831 randrp->virtualX = pScrn->virtualX; 832 randrp->virtualY = pScrn->virtualY; 833 } 834 xf86CrtcSetScreenSubpixelOrder (pScreen); 835#if RANDR_12_INTERFACE 836 if (xf86RandR12CreateScreenResources12 (pScreen)) 837 return TRUE; 838#endif 839 return TRUE; 840} 841 842 843Bool 844xf86RandR12Init (ScreenPtr pScreen) 845{ 846 rrScrPrivPtr rp; 847 XF86RandRInfoPtr randrp; 848 849#ifdef PANORAMIX 850 /* XXX disable RandR when using Xinerama */ 851 if (!noPanoramiXExtension) 852 { 853 if (xf86NumScreens == 1) 854 noPanoramiXExtension = TRUE; 855 else 856 return TRUE; 857 } 858#endif 859 860 if (xf86RandR12Generation != serverGeneration) 861 xf86RandR12Generation = serverGeneration; 862 863 xf86RandR12Key = &xf86RandR12KeyRec; 864 if (!dixRegisterPrivateKey(&xf86RandR12KeyRec, PRIVATE_SCREEN, 0)) 865 return FALSE; 866 867 randrp = malloc(sizeof (XF86RandRInfoRec)); 868 if (!randrp) 869 return FALSE; 870 871 if (!RRScreenInit(pScreen)) 872 { 873 free(randrp); 874 return FALSE; 875 } 876 rp = rrGetScrPriv(pScreen); 877 rp->rrGetInfo = xf86RandR12GetInfo; 878 rp->rrSetConfig = xf86RandR12SetConfig; 879 880 randrp->virtualX = -1; 881 randrp->virtualY = -1; 882 randrp->mmWidth = pScreen->mmWidth; 883 randrp->mmHeight = pScreen->mmHeight; 884 885 randrp->rotation = RR_Rotate_0; /* initial rotated mode */ 886 887 randrp->supported_rotations = RR_Rotate_0; 888 889 randrp->maxX = randrp->maxY = 0; 890 891 dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp); 892 893#if RANDR_12_INTERFACE 894 if (!xf86RandR12Init12 (pScreen)) 895 return FALSE; 896#endif 897 return TRUE; 898} 899 900void 901xf86RandR12CloseScreen (ScreenPtr pScreen) 902{ 903 XF86RandRInfoPtr randrp; 904 905 if (xf86RandR12Key == NULL) 906 return; 907 908 randrp = XF86RANDRINFO(pScreen); 909#if RANDR_12_INTERFACE 910 xf86Screens[pScreen->myNum]->EnterVT = randrp->orig_EnterVT; 911#endif 912 913 free(randrp); 914} 915 916void 917xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) 918{ 919 XF86RandRInfoPtr randrp; 920#if RANDR_12_INTERFACE 921 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 922 int c; 923 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 924#endif 925 926 if (xf86RandR12Key == NULL) 927 return; 928 929 randrp = XF86RANDRINFO(pScreen); 930#if RANDR_12_INTERFACE 931 for (c = 0; c < config->num_crtc; c++) { 932 xf86CrtcPtr crtc = config->crtc[c]; 933 934 RRCrtcSetRotations (crtc->randr_crtc, rotations); 935 } 936#endif 937 randrp->supported_rotations = rotations; 938} 939 940void 941xf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms) 942{ 943 XF86RandRInfoPtr randrp; 944#if RANDR_13_INTERFACE 945 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 946 int c; 947 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 948#endif 949 950 if (xf86RandR12Key == NULL) 951 return; 952 953 randrp = XF86RANDRINFO(pScreen); 954#if RANDR_13_INTERFACE 955 for (c = 0; c < config->num_crtc; c++) { 956 xf86CrtcPtr crtc = config->crtc[c]; 957 958 RRCrtcSetTransformSupport (crtc->randr_crtc, transforms); 959 } 960#endif 961} 962 963void 964xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) 965{ 966 ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; 967 968 if (xf86RandR12Generation != serverGeneration || 969 XF86RANDRINFO(pScreen)->virtualX == -1) 970 { 971 *x = pScrn->virtualX; 972 *y = pScrn->virtualY; 973 } else { 974 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 975 976 *x = randrp->virtualX; 977 *y = randrp->virtualY; 978 } 979} 980 981#if RANDR_12_INTERFACE 982 983#define FLAG_BITS (RR_HSyncPositive | \ 984 RR_HSyncNegative | \ 985 RR_VSyncPositive | \ 986 RR_VSyncNegative | \ 987 RR_Interlace | \ 988 RR_DoubleScan | \ 989 RR_CSync | \ 990 RR_CSyncPositive | \ 991 RR_CSyncNegative | \ 992 RR_HSkewPresent | \ 993 RR_BCast | \ 994 RR_PixelMultiplex | \ 995 RR_DoubleClock | \ 996 RR_ClockDivideBy2) 997 998static Bool 999xf86RandRModeMatches (RRModePtr randr_mode, 1000 DisplayModePtr mode) 1001{ 1002#if 0 1003 if (match_name) 1004 { 1005 /* check for same name */ 1006 int len = strlen (mode->name); 1007 if (randr_mode->mode.nameLength != len) return FALSE; 1008 if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE; 1009 } 1010#endif 1011 1012 /* check for same timings */ 1013 if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE; 1014 if (randr_mode->mode.width != mode->HDisplay) return FALSE; 1015 if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE; 1016 if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE; 1017 if (randr_mode->mode.hTotal != mode->HTotal) return FALSE; 1018 if (randr_mode->mode.hSkew != mode->HSkew) return FALSE; 1019 if (randr_mode->mode.height != mode->VDisplay) return FALSE; 1020 if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE; 1021 if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE; 1022 if (randr_mode->mode.vTotal != mode->VTotal) return FALSE; 1023 1024 /* check for same flags (using only the XF86 valid flag bits) */ 1025 if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) 1026 return FALSE; 1027 1028 /* everything matches */ 1029 return TRUE; 1030} 1031 1032static Bool 1033xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) 1034{ 1035 ScreenPtr pScreen = randr_crtc->pScreen; 1036 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1037 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1038 RRModePtr randr_mode = NULL; 1039 int x; 1040 int y; 1041 Rotation rotation; 1042 int numOutputs; 1043 RROutputPtr *randr_outputs; 1044 RROutputPtr randr_output; 1045 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1046 xf86OutputPtr output; 1047 int i, j; 1048 DisplayModePtr mode = &crtc->mode; 1049 Bool ret; 1050 1051 randr_outputs = malloc(config->num_output * sizeof (RROutputPtr)); 1052 if (!randr_outputs) 1053 return FALSE; 1054 x = crtc->x; 1055 y = crtc->y; 1056 rotation = crtc->rotation; 1057 numOutputs = 0; 1058 randr_mode = NULL; 1059 for (i = 0; i < config->num_output; i++) 1060 { 1061 output = config->output[i]; 1062 if (output->crtc == crtc) 1063 { 1064 randr_output = output->randr_output; 1065 randr_outputs[numOutputs++] = randr_output; 1066 /* 1067 * We make copies of modes, so pointer equality 1068 * isn't sufficient 1069 */ 1070 for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++) 1071 { 1072 RRModePtr m = (j < randr_output->numModes ? 1073 randr_output->modes[j] : 1074 randr_output->userModes[j-randr_output->numModes]); 1075 1076 if (xf86RandRModeMatches (m, mode)) 1077 { 1078 randr_mode = m; 1079 break; 1080 } 1081 } 1082 } 1083 } 1084 ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, 1085 rotation, 1086 crtc->transformPresent ? &crtc->transform : NULL, 1087 numOutputs, randr_outputs); 1088 free(randr_outputs); 1089 return ret; 1090} 1091 1092/* 1093 * Convert a RandR mode to a DisplayMode 1094 */ 1095static void 1096xf86RandRModeConvert (ScrnInfoPtr scrn, 1097 RRModePtr randr_mode, 1098 DisplayModePtr mode) 1099{ 1100 memset(mode, 0, sizeof(DisplayModeRec)); 1101 mode->status = MODE_OK; 1102 1103 mode->Clock = randr_mode->mode.dotClock / 1000; 1104 1105 mode->HDisplay = randr_mode->mode.width; 1106 mode->HSyncStart = randr_mode->mode.hSyncStart; 1107 mode->HSyncEnd = randr_mode->mode.hSyncEnd; 1108 mode->HTotal = randr_mode->mode.hTotal; 1109 mode->HSkew = randr_mode->mode.hSkew; 1110 1111 mode->VDisplay = randr_mode->mode.height; 1112 mode->VSyncStart = randr_mode->mode.vSyncStart; 1113 mode->VSyncEnd = randr_mode->mode.vSyncEnd; 1114 mode->VTotal = randr_mode->mode.vTotal; 1115 mode->VScan = 0; 1116 1117 mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; 1118 1119 xf86SetModeCrtc (mode, scrn->adjustFlags); 1120} 1121 1122static Bool 1123xf86RandR12CrtcSet (ScreenPtr pScreen, 1124 RRCrtcPtr randr_crtc, 1125 RRModePtr randr_mode, 1126 int x, 1127 int y, 1128 Rotation rotation, 1129 int num_randr_outputs, 1130 RROutputPtr *randr_outputs) 1131{ 1132 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1133 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1134 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1135 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1136 RRTransformPtr transform; 1137 Bool changed = FALSE; 1138 int o, ro; 1139 xf86CrtcPtr *save_crtcs; 1140 Bool save_enabled = crtc->enabled; 1141 1142 if (!crtc->scrn->vtSema) 1143 return FALSE; 1144 1145 save_crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr)); 1146 if ((randr_mode != NULL) != crtc->enabled) 1147 changed = TRUE; 1148 else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode)) 1149 changed = TRUE; 1150 1151 if (rotation != crtc->rotation) 1152 changed = TRUE; 1153 1154 transform = RRCrtcGetTransform (randr_crtc); 1155 if ((transform != NULL) != crtc->transformPresent) 1156 changed = TRUE; 1157 else if (transform && memcmp (&transform->transform, &crtc->transform.transform, 1158 sizeof (transform->transform)) != 0) 1159 changed = TRUE; 1160 1161 if (x != crtc->x || y != crtc->y) 1162 changed = TRUE; 1163 for (o = 0; o < config->num_output; o++) 1164 { 1165 xf86OutputPtr output = config->output[o]; 1166 xf86CrtcPtr new_crtc; 1167 1168 save_crtcs[o] = output->crtc; 1169 1170 if (output->crtc == crtc) 1171 new_crtc = NULL; 1172 else 1173 new_crtc = output->crtc; 1174 for (ro = 0; ro < num_randr_outputs; ro++) 1175 if (output->randr_output == randr_outputs[ro]) 1176 { 1177 new_crtc = crtc; 1178 break; 1179 } 1180 if (new_crtc != output->crtc) 1181 { 1182 changed = TRUE; 1183 output->crtc = new_crtc; 1184 } 1185 } 1186 for (ro = 0; ro < num_randr_outputs; ro++) 1187 if (randr_outputs[ro]->pendingProperties) 1188 changed = TRUE; 1189 1190 /* XXX need device-independent mode setting code through an API */ 1191 if (changed) 1192 { 1193 crtc->enabled = randr_mode != NULL; 1194 1195 if (randr_mode) 1196 { 1197 DisplayModeRec mode; 1198 RRTransformPtr transform = RRCrtcGetTransform (randr_crtc); 1199 1200 xf86RandRModeConvert (pScrn, randr_mode, &mode); 1201 if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y)) 1202 { 1203 crtc->enabled = save_enabled; 1204 for (o = 0; o < config->num_output; o++) 1205 { 1206 xf86OutputPtr output = config->output[o]; 1207 output->crtc = save_crtcs[o]; 1208 } 1209 free(save_crtcs); 1210 return FALSE; 1211 } 1212 xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height); 1213 xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); 1214 /* 1215 * Save the last successful setting for EnterVT 1216 */ 1217 crtc->desiredMode = mode; 1218 crtc->desiredRotation = rotation; 1219 if (transform) { 1220 crtc->desiredTransform = *transform; 1221 crtc->desiredTransformPresent = TRUE; 1222 } else 1223 crtc->desiredTransformPresent = FALSE; 1224 1225 crtc->desiredX = x; 1226 crtc->desiredY = y; 1227 } 1228 xf86DisableUnusedFunctions (pScrn); 1229 } 1230 free(save_crtcs); 1231 return xf86RandR12CrtcNotify (randr_crtc); 1232} 1233 1234static Bool 1235xf86RandR12CrtcSetGamma (ScreenPtr pScreen, 1236 RRCrtcPtr randr_crtc) 1237{ 1238 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1239 1240 if (crtc->funcs->gamma_set == NULL) 1241 return FALSE; 1242 1243 if (!crtc->scrn->vtSema) 1244 return TRUE; 1245 1246 /* Realloc local gamma if needed. */ 1247 if (randr_crtc->gammaSize != crtc->gamma_size) { 1248 CARD16 *tmp_ptr; 1249 tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16)); 1250 if (!tmp_ptr) 1251 return FALSE; 1252 crtc->gamma_red = tmp_ptr; 1253 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 1254 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 1255 } 1256 1257 crtc->gamma_size = randr_crtc->gammaSize; 1258 memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16)); 1259 memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16)); 1260 memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16)); 1261 1262 /* Only set it when the crtc is actually running. 1263 * Otherwise it will be set when it's activated. 1264 */ 1265 if (crtc->active) 1266 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 1267 crtc->gamma_blue, crtc->gamma_size); 1268 1269 return TRUE; 1270} 1271 1272static Bool 1273xf86RandR12CrtcGetGamma (ScreenPtr pScreen, 1274 RRCrtcPtr randr_crtc) 1275{ 1276 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1277 1278 if (!crtc->gamma_size) 1279 return FALSE; 1280 1281 if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue) 1282 return FALSE; 1283 1284 /* Realloc randr gamma if needed. */ 1285 if (randr_crtc->gammaSize != crtc->gamma_size) { 1286 CARD16 *tmp_ptr; 1287 tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16)); 1288 if (!tmp_ptr) 1289 return FALSE; 1290 randr_crtc->gammaRed = tmp_ptr; 1291 randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size; 1292 randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size; 1293 } 1294 randr_crtc->gammaSize = crtc->gamma_size; 1295 memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16)); 1296 memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16)); 1297 memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16)); 1298 1299 return TRUE; 1300} 1301 1302static Bool 1303xf86RandR12OutputSetProperty (ScreenPtr pScreen, 1304 RROutputPtr randr_output, 1305 Atom property, 1306 RRPropertyValuePtr value) 1307{ 1308 xf86OutputPtr output = randr_output->devPrivate; 1309 1310 /* If we don't have any property handler, then we don't care what the 1311 * user is setting properties to. 1312 */ 1313 if (output->funcs->set_property == NULL) 1314 return TRUE; 1315 1316 /* 1317 * This function gets called even when vtSema is FALSE, as 1318 * drivers will need to remember the correct value to apply 1319 * when the VT switch occurs 1320 */ 1321 return output->funcs->set_property(output, property, value); 1322} 1323 1324static Bool 1325xf86RandR13OutputGetProperty (ScreenPtr pScreen, 1326 RROutputPtr randr_output, 1327 Atom property) 1328{ 1329 xf86OutputPtr output = randr_output->devPrivate; 1330 1331 if (output->funcs->get_property == NULL) 1332 return TRUE; 1333 1334 /* Should be safe even w/o vtSema */ 1335 return output->funcs->get_property(output, property); 1336} 1337 1338static Bool 1339xf86RandR12OutputValidateMode (ScreenPtr pScreen, 1340 RROutputPtr randr_output, 1341 RRModePtr randr_mode) 1342{ 1343 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1344 xf86OutputPtr output = randr_output->devPrivate; 1345 DisplayModeRec mode; 1346 1347 xf86RandRModeConvert (pScrn, randr_mode, &mode); 1348 /* 1349 * This function may be called when vtSema is FALSE, so 1350 * the underlying function must either avoid touching the hardware 1351 * or return FALSE when vtSema is FALSE 1352 */ 1353 if (output->funcs->mode_valid (output, &mode) != MODE_OK) 1354 return FALSE; 1355 return TRUE; 1356} 1357 1358static void 1359xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) 1360{ 1361} 1362 1363/** 1364 * Given a list of xf86 modes and a RandR Output object, construct 1365 * RandR modes and assign them to the output 1366 */ 1367static Bool 1368xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) 1369{ 1370 DisplayModePtr mode; 1371 RRModePtr *rrmodes = NULL; 1372 int nmode = 0; 1373 int npreferred = 0; 1374 Bool ret = TRUE; 1375 int pref; 1376 1377 for (mode = modes; mode; mode = mode->next) 1378 nmode++; 1379 1380 if (nmode) { 1381 rrmodes = malloc(nmode * sizeof (RRModePtr)); 1382 1383 if (!rrmodes) 1384 return FALSE; 1385 nmode = 0; 1386 1387 for (pref = 1; pref >= 0; pref--) { 1388 for (mode = modes; mode; mode = mode->next) { 1389 if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { 1390 xRRModeInfo modeInfo; 1391 RRModePtr rrmode; 1392 1393 modeInfo.nameLength = strlen (mode->name); 1394 modeInfo.width = mode->HDisplay; 1395 modeInfo.dotClock = mode->Clock * 1000; 1396 modeInfo.hSyncStart = mode->HSyncStart; 1397 modeInfo.hSyncEnd = mode->HSyncEnd; 1398 modeInfo.hTotal = mode->HTotal; 1399 modeInfo.hSkew = mode->HSkew; 1400 1401 modeInfo.height = mode->VDisplay; 1402 modeInfo.vSyncStart = mode->VSyncStart; 1403 modeInfo.vSyncEnd = mode->VSyncEnd; 1404 modeInfo.vTotal = mode->VTotal; 1405 modeInfo.modeFlags = mode->Flags; 1406 1407 rrmode = RRModeGet (&modeInfo, mode->name); 1408 if (rrmode) { 1409 rrmodes[nmode++] = rrmode; 1410 npreferred += pref; 1411 } 1412 } 1413 } 1414 } 1415 } 1416 1417 ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); 1418 free(rrmodes); 1419 return ret; 1420} 1421 1422/* 1423 * Mirror the current mode configuration to RandR 1424 */ 1425static Bool 1426xf86RandR12SetInfo12 (ScreenPtr pScreen) 1427{ 1428 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1429 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1430 RROutputPtr *clones; 1431 RRCrtcPtr *crtcs; 1432 int ncrtc; 1433 int o, c, l; 1434 RRCrtcPtr randr_crtc; 1435 int nclone; 1436 1437 clones = malloc(config->num_output * sizeof (RROutputPtr)); 1438 crtcs = malloc(config->num_crtc * sizeof (RRCrtcPtr)); 1439 for (o = 0; o < config->num_output; o++) 1440 { 1441 xf86OutputPtr output = config->output[o]; 1442 1443 ncrtc = 0; 1444 for (c = 0; c < config->num_crtc; c++) 1445 if (output->possible_crtcs & (1 << c)) 1446 crtcs[ncrtc++] = config->crtc[c]->randr_crtc; 1447 1448 if (output->crtc) 1449 randr_crtc = output->crtc->randr_crtc; 1450 else 1451 randr_crtc = NULL; 1452 1453 if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) 1454 { 1455 free(crtcs); 1456 free(clones); 1457 return FALSE; 1458 } 1459 1460 RROutputSetPhysicalSize(output->randr_output, 1461 output->mm_width, 1462 output->mm_height); 1463 xf86RROutputSetModes (output->randr_output, output->probed_modes); 1464 1465 switch (output->status) { 1466 case XF86OutputStatusConnected: 1467 RROutputSetConnection (output->randr_output, RR_Connected); 1468 break; 1469 case XF86OutputStatusDisconnected: 1470 RROutputSetConnection (output->randr_output, RR_Disconnected); 1471 break; 1472 case XF86OutputStatusUnknown: 1473 RROutputSetConnection (output->randr_output, RR_UnknownConnection); 1474 break; 1475 } 1476 1477 RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); 1478 1479 /* 1480 * Valid clones 1481 */ 1482 nclone = 0; 1483 for (l = 0; l < config->num_output; l++) 1484 { 1485 xf86OutputPtr clone = config->output[l]; 1486 1487 if (l != o && (output->possible_clones & (1 << l))) 1488 clones[nclone++] = clone->randr_output; 1489 } 1490 if (!RROutputSetClones (output->randr_output, clones, nclone)) 1491 { 1492 free(crtcs); 1493 free(clones); 1494 return FALSE; 1495 } 1496 } 1497 free(crtcs); 1498 free(clones); 1499 return TRUE; 1500} 1501 1502 1503 1504/* 1505 * Query the hardware for the current state, then mirror 1506 * that to RandR 1507 */ 1508static Bool 1509xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) 1510{ 1511 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1512 1513 if (!pScrn->vtSema) 1514 return TRUE; 1515 xf86ProbeOutputModes (pScrn, 0, 0); 1516 xf86SetScrnInfoModes (pScrn); 1517 return xf86RandR12SetInfo12 (pScreen); 1518} 1519 1520static Bool 1521xf86RandR12CreateObjects12 (ScreenPtr pScreen) 1522{ 1523 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1524 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1525 int c; 1526 int o; 1527 1528 if (!RRInit ()) 1529 return FALSE; 1530 1531 /* 1532 * Configure crtcs 1533 */ 1534 for (c = 0; c < config->num_crtc; c++) 1535 { 1536 xf86CrtcPtr crtc = config->crtc[c]; 1537 1538 crtc->randr_crtc = RRCrtcCreate (pScreen, crtc); 1539 RRCrtcGammaSetSize (crtc->randr_crtc, 256); 1540 } 1541 /* 1542 * Configure outputs 1543 */ 1544 for (o = 0; o < config->num_output; o++) 1545 { 1546 xf86OutputPtr output = config->output[o]; 1547 1548 output->randr_output = RROutputCreate (pScreen, output->name, 1549 strlen (output->name), 1550 output); 1551 1552 if (output->funcs->create_resources != NULL) 1553 output->funcs->create_resources(output); 1554 RRPostPendingProperties (output->randr_output); 1555 } 1556 return TRUE; 1557} 1558 1559static Bool 1560xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) 1561{ 1562 int c; 1563 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1564 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1565 1566 if (xf86RandR12Key == NULL) 1567 return TRUE; 1568 1569 for (c = 0; c < config->num_crtc; c++) 1570 xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); 1571 1572 RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight, 1573 config->maxWidth, config->maxHeight); 1574 return TRUE; 1575} 1576 1577/* 1578 * Something happened within the screen configuration due 1579 * to DGA, VidMode or hot key. Tell RandR 1580 */ 1581 1582void 1583xf86RandR12TellChanged (ScreenPtr pScreen) 1584{ 1585 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1586 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1587 int c; 1588 1589 if (xf86RandR12Key == NULL) 1590 return; 1591 1592 xf86RandR12SetInfo12 (pScreen); 1593 for (c = 0; c < config->num_crtc; c++) 1594 xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); 1595 1596 RRTellChanged (pScreen); 1597} 1598 1599static void 1600xf86RandR12PointerMoved (int scrnIndex, int x, int y) 1601{ 1602 ScreenPtr pScreen = screenInfo.screens[scrnIndex]; 1603 ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); 1604 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1605 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1606 int c; 1607 1608 randrp->pointerX = x; 1609 randrp->pointerY = y; 1610 for (c = 0; c < config->num_crtc; c++) 1611 xf86RandR13Pan (config->crtc[c], x, y); 1612} 1613 1614static Bool 1615xf86RandR13GetPanning (ScreenPtr pScreen, 1616 RRCrtcPtr randr_crtc, 1617 BoxPtr totalArea, 1618 BoxPtr trackingArea, 1619 INT16 *border) 1620{ 1621 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1622 1623 if (crtc->version < 2) 1624 return FALSE; 1625 if (totalArea) 1626 memcpy (totalArea, &crtc->panningTotalArea, sizeof(BoxRec)); 1627 if (trackingArea) 1628 memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); 1629 if (border) 1630 memcpy (border, crtc->panningBorder, 4*sizeof(INT16)); 1631 1632 return TRUE; 1633} 1634 1635static Bool 1636xf86RandR13SetPanning (ScreenPtr pScreen, 1637 RRCrtcPtr randr_crtc, 1638 BoxPtr totalArea, 1639 BoxPtr trackingArea, 1640 INT16 *border) 1641{ 1642 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1643 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1644 BoxRec oldTotalArea; 1645 BoxRec oldTrackingArea; 1646 INT16 oldBorder[4]; 1647 1648 1649 if (crtc->version < 2) 1650 return FALSE; 1651 1652 memcpy (&oldTotalArea, &crtc->panningTotalArea, sizeof(BoxRec)); 1653 memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); 1654 memcpy (oldBorder, crtc->panningBorder, 4*sizeof(INT16)); 1655 1656 if (totalArea) 1657 memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec)); 1658 if (trackingArea) 1659 memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec)); 1660 if (border) 1661 memcpy (crtc->panningBorder, border, 4*sizeof(INT16)); 1662 1663 if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) { 1664 xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY); 1665 return TRUE; 1666 } else { 1667 /* Restore old settings */ 1668 memcpy (&crtc->panningTotalArea, &oldTotalArea, sizeof(BoxRec)); 1669 memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec)); 1670 memcpy (crtc->panningBorder, oldBorder, 4*sizeof(INT16)); 1671 return FALSE; 1672 } 1673} 1674 1675/* 1676 * Compatibility with XF86VidMode's gamma changer. This necessarily clobbers 1677 * any per-crtc setup. You asked for it... 1678 */ 1679 1680static void 1681gamma_to_ramp(float gamma, CARD16 *ramp, int size) 1682{ 1683 int i; 1684 1685 for (i = 0; i < size; i++) { 1686 if (gamma == 1.0) 1687 ramp[i] = i << 8; 1688 else 1689 ramp[i] = (CARD16)(pow((double)i / (double)(size - 1), 1. / gamma) 1690 * (double)(size - 1) * 256); 1691 } 1692} 1693 1694static int 1695xf86RandR12ChangeGamma(int scrnIndex, Gamma gamma) 1696{ 1697 CARD16 *points, *red, *green, *blue; 1698 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 1699 RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn); 1700 int size; 1701 1702 if (!crtc) 1703 return Success; 1704 1705 size = max(0, crtc->gammaSize); 1706 if (!size) 1707 return Success; 1708 1709 points = calloc(size, 3 * sizeof(CARD16)); 1710 if (!points) 1711 return BadAlloc; 1712 1713 red = points; 1714 green = points + size; 1715 blue = points + 2 * size; 1716 1717 gamma_to_ramp(gamma.red, red, size); 1718 gamma_to_ramp(gamma.green, green, size); 1719 gamma_to_ramp(gamma.blue, blue, size); 1720 RRCrtcGammaSet(crtc, red, green, blue); 1721 1722 free(points); 1723 1724 pScrn->gamma = gamma; 1725 1726 return Success; 1727} 1728 1729static Bool 1730xf86RandR12EnterVT (int screen_index, int flags) 1731{ 1732 ScreenPtr pScreen = screenInfo.screens[screen_index]; 1733 ScrnInfoPtr pScrn = xf86Screens[screen_index]; 1734 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1735 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 1736 Bool ret; 1737 1738 if (randrp->orig_EnterVT) { 1739 pScrn->EnterVT = randrp->orig_EnterVT; 1740 ret = pScrn->EnterVT (screen_index, flags); 1741 randrp->orig_EnterVT = pScrn->EnterVT; 1742 pScrn->EnterVT = xf86RandR12EnterVT; 1743 if (!ret) 1744 return FALSE; 1745 } 1746 1747 /* reload gamma */ 1748 int i; 1749 for (i = 0; i < rp->numCrtcs; i++) 1750 xf86RandR12CrtcSetGamma(pScreen, rp->crtcs[i]); 1751 1752 return RRGetInfo (pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */ 1753} 1754 1755static Bool 1756xf86RandR12Init12 (ScreenPtr pScreen) 1757{ 1758 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1759 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 1760 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1761 int i; 1762 1763 rp->rrGetInfo = xf86RandR12GetInfo12; 1764 rp->rrScreenSetSize = xf86RandR12ScreenSetSize; 1765 rp->rrCrtcSet = xf86RandR12CrtcSet; 1766 rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; 1767 rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma; 1768 rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; 1769 rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; 1770#if RANDR_13_INTERFACE 1771 rp->rrOutputGetProperty = xf86RandR13OutputGetProperty; 1772 rp->rrGetPanning = xf86RandR13GetPanning; 1773 rp->rrSetPanning = xf86RandR13SetPanning; 1774#endif 1775 rp->rrModeDestroy = xf86RandR12ModeDestroy; 1776 rp->rrSetConfig = NULL; 1777 pScrn->PointerMoved = xf86RandR12PointerMoved; 1778 pScrn->ChangeGamma = xf86RandR12ChangeGamma; 1779 1780 randrp->orig_EnterVT = pScrn->EnterVT; 1781 pScrn->EnterVT = xf86RandR12EnterVT; 1782 1783 if (!xf86RandR12CreateObjects12 (pScreen)) 1784 return FALSE; 1785 1786 /* 1787 * Configure output modes 1788 */ 1789 if (!xf86RandR12SetInfo12 (pScreen)) 1790 return FALSE; 1791 for (i = 0; i < rp->numCrtcs; i++) { 1792 xf86RandR12CrtcGetGamma(pScreen, rp->crtcs[i]); 1793 } 1794 return TRUE; 1795} 1796 1797#endif 1798 1799Bool 1800xf86RandR12PreInit (ScrnInfoPtr pScrn) 1801{ 1802 return TRUE; 1803} 1804