xf86RandR12.c (75203B)
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 #endif 26 27 #include "xf86.h" 28 #include "os.h" 29 #include "globals.h" 30 #include "xf86Modes.h" 31 #include "xf86Priv.h" 32 #include "xf86DDC.h" 33 #include "mipointer.h" 34 #include "windowstr.h" 35 #include "inputstr.h" 36 #include <randrstr.h> 37 #include <X11/extensions/render.h> 38 39 #include "xf86cmap.h" 40 #include "xf86Crtc.h" 41 #include "xf86RandR12.h" 42 43 typedef struct _xf86RandR12Info { 44 int virtualX; 45 int virtualY; 46 int mmWidth; 47 int mmHeight; 48 int maxX; 49 int maxY; 50 int pointerX; 51 int pointerY; 52 Rotation rotation; /* current mode */ 53 Rotation supported_rotations; /* driver supported */ 54 55 /* Compatibility with colormaps and XF86VidMode's gamma */ 56 int palette_red_size; 57 int palette_green_size; 58 int palette_blue_size; 59 int palette_size; 60 LOCO *palette; 61 62 /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends 63 * (actually, any time that we switch back into our VT). 64 * 65 * See https://bugs.freedesktop.org/show_bug.cgi?id=21554 66 */ 67 xf86EnterVTProc *orig_EnterVT; 68 69 Bool panning; 70 ConstrainCursorHarderProcPtr orig_ConstrainCursorHarder; 71 } XF86RandRInfoRec, *XF86RandRInfoPtr; 72 73 #ifdef RANDR_12_INTERFACE 74 static Bool xf86RandR12Init12(ScreenPtr pScreen); 75 static Bool xf86RandR12CreateScreenResources12(ScreenPtr pScreen); 76 #endif 77 78 static int xf86RandR12Generation; 79 80 static DevPrivateKeyRec xf86RandR12KeyRec; 81 82 #define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \ 83 dixLookupPrivate(&(p)->devPrivates, &xf86RandR12KeyRec)) 84 85 static int 86 xf86RandR12ModeRefresh(DisplayModePtr mode) 87 { 88 if (mode->VRefresh) 89 return (int) (mode->VRefresh + 0.5); 90 else 91 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); 92 } 93 94 /* Adapt panning area; return TRUE if panning area was valid without adaption */ 95 static int 96 xf86RandR13VerifyPanningArea(xf86CrtcPtr crtc, int screenWidth, 97 int screenHeight) 98 { 99 int ret = TRUE; 100 101 if (crtc->version < 2) 102 return FALSE; 103 104 if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) { 105 /* Panning in X is disabled */ 106 if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2) 107 /* Illegal configuration -> fail/disable */ 108 ret = FALSE; 109 crtc->panningTotalArea.x1 = crtc->panningTotalArea.x2 = 0; 110 crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0; 111 crtc->panningBorder[0] = crtc->panningBorder[2] = 0; 112 } 113 else { 114 /* Panning in X is enabled */ 115 if (crtc->panningTotalArea.x1 < 0) { 116 /* Panning region outside screen -> move inside */ 117 crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1; 118 crtc->panningTotalArea.x1 = 0; 119 ret = FALSE; 120 } 121 if (crtc->panningTotalArea.x2 < 122 crtc->panningTotalArea.x1 + crtc->mode.HDisplay) { 123 /* Panning region smaller than displayed area -> crop to displayed area */ 124 crtc->panningTotalArea.x2 = 125 crtc->panningTotalArea.x1 + crtc->mode.HDisplay; 126 ret = FALSE; 127 } 128 if (crtc->panningTotalArea.x2 > screenWidth) { 129 /* Panning region larger than screen -> move inside, then crop to screen */ 130 crtc->panningTotalArea.x1 -= 131 crtc->panningTotalArea.x2 - screenWidth; 132 crtc->panningTotalArea.x2 = screenWidth; 133 ret = FALSE; 134 if (crtc->panningTotalArea.x1 < 0) 135 crtc->panningTotalArea.x1 = 0; 136 } 137 if (crtc->panningBorder[0] + crtc->panningBorder[2] > 138 crtc->mode.HDisplay) { 139 /* Borders too large -> set to 0 */ 140 crtc->panningBorder[0] = crtc->panningBorder[2] = 0; 141 ret = FALSE; 142 } 143 } 144 145 if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) { 146 /* Panning in Y is disabled */ 147 if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2) 148 /* Illegal configuration -> fail/disable */ 149 ret = FALSE; 150 crtc->panningTotalArea.y1 = crtc->panningTotalArea.y2 = 0; 151 crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0; 152 crtc->panningBorder[1] = crtc->panningBorder[3] = 0; 153 } 154 else { 155 /* Panning in Y is enabled */ 156 if (crtc->panningTotalArea.y1 < 0) { 157 /* Panning region outside screen -> move inside */ 158 crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1; 159 crtc->panningTotalArea.y1 = 0; 160 ret = FALSE; 161 } 162 if (crtc->panningTotalArea.y2 < 163 crtc->panningTotalArea.y1 + crtc->mode.VDisplay) { 164 /* Panning region smaller than displayed area -> crop to displayed area */ 165 crtc->panningTotalArea.y2 = 166 crtc->panningTotalArea.y1 + crtc->mode.VDisplay; 167 ret = FALSE; 168 } 169 if (crtc->panningTotalArea.y2 > screenHeight) { 170 /* Panning region larger than screen -> move inside, then crop to screen */ 171 crtc->panningTotalArea.y1 -= 172 crtc->panningTotalArea.y2 - screenHeight; 173 crtc->panningTotalArea.y2 = screenHeight; 174 ret = FALSE; 175 if (crtc->panningTotalArea.y1 < 0) 176 crtc->panningTotalArea.y1 = 0; 177 } 178 if (crtc->panningBorder[1] + crtc->panningBorder[3] > 179 crtc->mode.VDisplay) { 180 /* Borders too large -> set to 0 */ 181 crtc->panningBorder[1] = crtc->panningBorder[3] = 0; 182 ret = FALSE; 183 } 184 } 185 186 return ret; 187 } 188 189 /* 190 * The heart of the panning operation: 191 * 192 * Given a frame buffer position (fb_x, fb_y), 193 * and a crtc position (crtc_x, crtc_y), 194 * and a transform matrix which maps frame buffer to crtc, 195 * compute a panning position (pan_x, pan_y) that 196 * makes the resulting transform line those two up 197 */ 198 199 static void 200 xf86ComputeCrtcPan(Bool transform_in_use, 201 struct pixman_f_transform *m, 202 double screen_x, double screen_y, 203 double crtc_x, double crtc_y, 204 int old_pan_x, int old_pan_y, int *new_pan_x, int *new_pan_y) 205 { 206 if (transform_in_use) { 207 /* 208 * Given the current transform, M, the current position 209 * on the Screen, S, and the desired position on the CRTC, 210 * C, compute a translation, T, such that: 211 * 212 * M T S = C 213 * 214 * where T is of the form 215 * 216 * | 1 0 dx | 217 * | 0 1 dy | 218 * | 0 0 1 | 219 * 220 * M T S = 221 * | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 | | Cx F | 222 * | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F | 223 * | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 | | F | 224 * 225 * R = M S 226 * 227 * Cx F = M00 dx + M01 dy + R0 228 * Cy F = M10 dx + M11 dy + R1 229 * F = M20 dx + M21 dy + R2 230 * 231 * Zero out dx, then dy 232 * 233 * F (Cx M10 - Cy M00) = 234 * (M10 M01 - M00 M11) dy + M10 R0 - M00 R1 235 * F (M10 - Cy M20) = 236 * (M10 M21 - M20 M11) dy + M10 R2 - M20 R1 237 * 238 * F (Cx M11 - Cy M01) = 239 * (M11 M00 - M01 M10) dx + M11 R0 - M01 R1 240 * F (M11 - Cy M21) = 241 * (M11 M20 - M21 M10) dx + M11 R2 - M21 R1 242 * 243 * Make some temporaries 244 * 245 * T = | Cx M10 - Cy M00 | 246 * | Cx M11 - Cy M01 | 247 * 248 * U = | M10 M01 - M00 M11 | 249 * | M11 M00 - M01 M10 | 250 * 251 * Q = | M10 R0 - M00 R1 | 252 * | M11 R0 - M01 R1 | 253 * 254 * P = | M10 - Cy M20 | 255 * | M11 - Cy M21 | 256 * 257 * W = | M10 M21 - M20 M11 | 258 * | M11 M20 - M21 M10 | 259 * 260 * V = | M10 R2 - M20 R1 | 261 * | M11 R2 - M21 R1 | 262 * 263 * Rewrite: 264 * 265 * F T0 = U0 dy + Q0 266 * F P0 = W0 dy + V0 267 * F T1 = U1 dx + Q1 268 * F P1 = W1 dx + V1 269 * 270 * Solve for F (two ways) 271 * 272 * F (W0 T0 - U0 P0) = W0 Q0 - U0 V0 273 * 274 * W0 Q0 - U0 V0 275 * F = ------------- 276 * W0 T0 - U0 P0 277 * 278 * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1 279 * 280 * W1 Q1 - U1 V1 281 * F = ------------- 282 * W1 T1 - U1 P1 283 * 284 * We'll use which ever solution works (denominator != 0) 285 * 286 * Finally, solve for dx and dy: 287 * 288 * dx = (F T1 - Q1) / U1 289 * dx = (F P1 - V1) / W1 290 * 291 * dy = (F T0 - Q0) / U0 292 * dy = (F P0 - V0) / W0 293 */ 294 double r[3]; 295 double q[2], u[2], t[2], v[2], w[2], p[2]; 296 double f; 297 struct pict_f_vector d; 298 int i; 299 300 /* Get the un-normalized crtc coordinates again */ 301 for (i = 0; i < 3; i++) 302 r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2]; 303 304 /* Combine values into temporaries */ 305 for (i = 0; i < 2; i++) { 306 q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1]; 307 u[i] = m->m[1][i] * m->m[0][1 - i] - m->m[0][i] * m->m[1][1 - i]; 308 t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y; 309 310 v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1]; 311 w[i] = m->m[1][i] * m->m[2][1 - i] - m->m[2][i] * m->m[1][1 - i]; 312 p[i] = m->m[1][i] - m->m[2][i] * crtc_y; 313 } 314 315 /* Find a way to compute f */ 316 f = 0; 317 for (i = 0; i < 2; i++) { 318 double a = w[i] * q[i] - u[i] * v[i]; 319 double b = w[i] * t[i] - u[i] * p[i]; 320 321 if (b != 0) { 322 f = a / b; 323 break; 324 } 325 } 326 327 /* Solve for the resulting transform vector */ 328 for (i = 0; i < 2; i++) { 329 if (u[i]) 330 d.v[1 - i] = (t[i] * f - q[i]) / u[i]; 331 else if (w[1]) 332 d.v[1 - i] = (p[i] * f - v[i]) / w[i]; 333 else 334 d.v[1 - i] = 0; 335 } 336 *new_pan_x = old_pan_x - floor(d.v[0] + 0.5); 337 *new_pan_y = old_pan_y - floor(d.v[1] + 0.5); 338 } 339 else { 340 *new_pan_x = screen_x - crtc_x; 341 *new_pan_y = screen_y - crtc_y; 342 } 343 } 344 345 static void 346 xf86RandR13Pan(xf86CrtcPtr crtc, int x, int y) 347 { 348 int newX, newY; 349 int width, height; 350 Bool panned = FALSE; 351 352 if (crtc->version < 2) 353 return; 354 355 if (!crtc->enabled || 356 (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 && 357 crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1)) 358 return; 359 360 newX = crtc->x; 361 newY = crtc->y; 362 width = crtc->mode.HDisplay; 363 height = crtc->mode.VDisplay; 364 365 if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 || 366 (x >= crtc->panningTrackingArea.x1 && 367 x < crtc->panningTrackingArea.x2)) && 368 (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 || 369 (y >= crtc->panningTrackingArea.y1 && 370 y < crtc->panningTrackingArea.y2))) { 371 struct pict_f_vector c; 372 373 /* 374 * Pre-clip the mouse position to the panning area so that we don't 375 * push the crtc outside. This doesn't deal with changes to the 376 * panning values, only mouse position changes. 377 */ 378 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { 379 if (x < crtc->panningTotalArea.x1) 380 x = crtc->panningTotalArea.x1; 381 if (x >= crtc->panningTotalArea.x2) 382 x = crtc->panningTotalArea.x2 - 1; 383 } 384 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 385 if (y < crtc->panningTotalArea.y1) 386 y = crtc->panningTotalArea.y1; 387 if (y >= crtc->panningTotalArea.y2) 388 y = crtc->panningTotalArea.y2 - 1; 389 } 390 391 c.v[0] = x; 392 c.v[1] = y; 393 c.v[2] = 1.0; 394 if (crtc->transform_in_use) { 395 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c); 396 } 397 else { 398 c.v[0] -= crtc->x; 399 c.v[1] -= crtc->y; 400 } 401 402 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { 403 if (c.v[0] < crtc->panningBorder[0]) { 404 c.v[0] = crtc->panningBorder[0]; 405 panned = TRUE; 406 } 407 if (c.v[0] >= width - crtc->panningBorder[2]) { 408 c.v[0] = width - crtc->panningBorder[2] - 1; 409 panned = TRUE; 410 } 411 } 412 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 413 if (c.v[1] < crtc->panningBorder[1]) { 414 c.v[1] = crtc->panningBorder[1]; 415 panned = TRUE; 416 } 417 if (c.v[1] >= height - crtc->panningBorder[3]) { 418 c.v[1] = height - crtc->panningBorder[3] - 1; 419 panned = TRUE; 420 } 421 } 422 if (panned) 423 xf86ComputeCrtcPan(crtc->transform_in_use, 424 &crtc->f_framebuffer_to_crtc, 425 x, y, c.v[0], c.v[1], newX, newY, &newX, &newY); 426 } 427 428 /* 429 * Ensure that the crtc is within the panning region. 430 * 431 * XXX This computation only works when we do not have a transform 432 * in use. 433 */ 434 if (!crtc->transform_in_use) { 435 /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */ 436 if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) { 437 if (newX > crtc->panningTotalArea.x2 - width) 438 newX = crtc->panningTotalArea.x2 - width; 439 if (newX < crtc->panningTotalArea.x1) 440 newX = crtc->panningTotalArea.x1; 441 } 442 if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) { 443 if (newY > crtc->panningTotalArea.y2 - height) 444 newY = crtc->panningTotalArea.y2 - height; 445 if (newY < crtc->panningTotalArea.y1) 446 newY = crtc->panningTotalArea.y1; 447 } 448 } 449 if (newX != crtc->x || newY != crtc->y) 450 xf86CrtcSetOrigin(crtc, newX, newY); 451 } 452 453 static Bool 454 xf86RandR12GetInfo(ScreenPtr pScreen, Rotation * rotations) 455 { 456 RRScreenSizePtr pSize; 457 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen); 458 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 459 DisplayModePtr mode; 460 int maxX = 0, maxY = 0; 461 462 *rotations = randrp->supported_rotations; 463 464 if (randrp->virtualX == -1 || randrp->virtualY == -1) { 465 randrp->virtualX = scrp->virtualX; 466 randrp->virtualY = scrp->virtualY; 467 } 468 469 /* Re-probe the outputs for new monitors or modes */ 470 if (scrp->vtSema) { 471 xf86ProbeOutputModes(scrp, 0, 0); 472 xf86SetScrnInfoModes(scrp); 473 } 474 475 for (mode = scrp->modes;; mode = mode->next) { 476 int refresh = xf86RandR12ModeRefresh(mode); 477 478 if (randrp->maxX == 0 || randrp->maxY == 0) { 479 if (maxX < mode->HDisplay) 480 maxX = mode->HDisplay; 481 if (maxY < mode->VDisplay) 482 maxY = mode->VDisplay; 483 } 484 pSize = RRRegisterSize(pScreen, 485 mode->HDisplay, mode->VDisplay, 486 randrp->mmWidth, randrp->mmHeight); 487 if (!pSize) 488 return FALSE; 489 RRRegisterRate(pScreen, pSize, refresh); 490 491 if (xf86ModesEqual(mode, scrp->currentMode)) { 492 RRSetCurrentConfig(pScreen, randrp->rotation, refresh, pSize); 493 } 494 if (mode->next == scrp->modes) 495 break; 496 } 497 498 if (randrp->maxX == 0 || randrp->maxY == 0) { 499 randrp->maxX = maxX; 500 randrp->maxY = maxY; 501 } 502 503 return TRUE; 504 } 505 506 static Bool 507 xf86RandR12SetMode(ScreenPtr pScreen, 508 DisplayModePtr mode, 509 Bool useVirtual, int mmWidth, int mmHeight) 510 { 511 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen); 512 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 513 int oldWidth = pScreen->width; 514 int oldHeight = pScreen->height; 515 int oldmmWidth = pScreen->mmWidth; 516 int oldmmHeight = pScreen->mmHeight; 517 WindowPtr pRoot = pScreen->root; 518 DisplayModePtr currentMode = NULL; 519 Bool ret = TRUE; 520 521 if (pRoot) 522 (*scrp->EnableDisableFBAccess) (scrp, FALSE); 523 if (useVirtual) { 524 scrp->virtualX = randrp->virtualX; 525 scrp->virtualY = randrp->virtualY; 526 } 527 else { 528 scrp->virtualX = mode->HDisplay; 529 scrp->virtualY = mode->VDisplay; 530 } 531 532 if (randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 533 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ 534 pScreen->width = scrp->virtualY; 535 pScreen->height = scrp->virtualX; 536 pScreen->mmWidth = mmHeight; 537 pScreen->mmHeight = mmWidth; 538 } 539 else { 540 pScreen->width = scrp->virtualX; 541 pScreen->height = scrp->virtualY; 542 pScreen->mmWidth = mmWidth; 543 pScreen->mmHeight = mmHeight; 544 } 545 if (scrp->currentMode == mode) { 546 /* Save current mode */ 547 currentMode = scrp->currentMode; 548 /* Reset, just so we ensure the drivers SwitchMode is called */ 549 scrp->currentMode = NULL; 550 } 551 /* 552 * We know that if the driver failed to SwitchMode to the rotated 553 * version, then it should revert back to its prior mode. 554 */ 555 if (!xf86SwitchMode(pScreen, mode)) { 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) (scrp, TRUE); 576 return ret; 577 } 578 579 Bool 580 xf86RandR12SetConfig(ScreenPtr pScreen, 581 Rotation rotation, int rate, RRScreenSizePtr pSize) 582 { 583 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen); 584 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 585 DisplayModePtr mode; 586 int pos[MAXDEVICES][2]; 587 Bool useVirtual = FALSE; 588 int maxX = 0, maxY = 0; 589 Rotation oldRotation = randrp->rotation; 590 DeviceIntPtr dev; 591 Bool view_adjusted = FALSE; 592 593 randrp->rotation = rotation; 594 595 if (randrp->virtualX == -1 || randrp->virtualY == -1) { 596 randrp->virtualX = scrp->virtualX; 597 randrp->virtualY = scrp->virtualY; 598 } 599 600 for (dev = inputInfo.devices; dev; dev = dev->next) { 601 if (!IsMaster(dev) && !IsFloating(dev)) 602 continue; 603 604 miPointerGetPosition(dev, &pos[dev->id][0], &pos[dev->id][1]); 605 } 606 607 for (mode = scrp->modes;; mode = mode->next) { 608 if (randrp->maxX == 0 || randrp->maxY == 0) { 609 if (maxX < mode->HDisplay) 610 maxX = mode->HDisplay; 611 if (maxY < mode->VDisplay) 612 maxY = mode->VDisplay; 613 } 614 if (mode->HDisplay == pSize->width && 615 mode->VDisplay == pSize->height && 616 (rate == 0 || xf86RandR12ModeRefresh(mode) == rate)) 617 break; 618 if (mode->next == scrp->modes) { 619 if (pSize->width == randrp->virtualX && 620 pSize->height == randrp->virtualY) { 621 mode = scrp->modes; 622 useVirtual = TRUE; 623 break; 624 } 625 if (randrp->maxX == 0 || randrp->maxY == 0) { 626 randrp->maxX = maxX; 627 randrp->maxY = maxY; 628 } 629 return FALSE; 630 } 631 } 632 633 if (randrp->maxX == 0 || randrp->maxY == 0) { 634 randrp->maxX = maxX; 635 randrp->maxY = maxY; 636 } 637 638 if (!xf86RandR12SetMode(pScreen, mode, useVirtual, pSize->mmWidth, 639 pSize->mmHeight)) { 640 randrp->rotation = oldRotation; 641 return FALSE; 642 } 643 644 /* 645 * Move the cursor back where it belongs; SwitchMode repositions it 646 * FIXME: duplicated code, see modes/xf86RandR12.c 647 */ 648 for (dev = inputInfo.devices; dev; dev = dev->next) { 649 if (!IsMaster(dev) && !IsFloating(dev)) 650 continue; 651 652 if (pScreen == miPointerGetScreen(dev)) { 653 int px = pos[dev->id][0]; 654 int py = pos[dev->id][1]; 655 656 px = (px >= pScreen->width ? (pScreen->width - 1) : px); 657 py = (py >= pScreen->height ? (pScreen->height - 1) : py); 658 659 /* Setting the viewpoint makes only sense on one device */ 660 if (!view_adjusted && IsMaster(dev)) { 661 xf86SetViewport(pScreen, px, py); 662 view_adjusted = TRUE; 663 } 664 665 (*pScreen->SetCursorPosition) (dev, pScreen, px, py, FALSE); 666 } 667 } 668 669 return TRUE; 670 } 671 672 #define PANNING_ENABLED(crtc) \ 673 ((crtc)->panningTotalArea.x2 > (crtc)->panningTotalArea.x1 || \ 674 (crtc)->panningTotalArea.y2 > (crtc)->panningTotalArea.y1) 675 676 static Bool 677 xf86RandR12ScreenSetSize(ScreenPtr pScreen, 678 CARD16 width, 679 CARD16 height, CARD32 mmWidth, CARD32 mmHeight) 680 { 681 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 682 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 683 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 684 WindowPtr pRoot = pScreen->root; 685 PixmapPtr pScrnPix; 686 Bool ret = FALSE; 687 int c; 688 689 if (randrp->virtualX == -1 || randrp->virtualY == -1) { 690 randrp->virtualX = pScrn->virtualX; 691 randrp->virtualY = pScrn->virtualY; 692 } 693 if (pRoot && pScrn->vtSema) 694 (*pScrn->EnableDisableFBAccess) (pScrn, FALSE); 695 696 /* Let the driver update virtualX and virtualY */ 697 if (!(*config->funcs->resize) (pScrn, width, height)) 698 goto finish; 699 700 ret = TRUE; 701 /* Update panning information */ 702 for (c = 0; c < config->num_crtc; c++) { 703 xf86CrtcPtr crtc = config->crtc[c]; 704 705 if (PANNING_ENABLED (crtc)) { 706 if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1) 707 crtc->panningTotalArea.x2 += width - pScreen->width; 708 if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1) 709 crtc->panningTotalArea.y2 += height - pScreen->height; 710 if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1) 711 crtc->panningTrackingArea.x2 += width - pScreen->width; 712 if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1) 713 crtc->panningTrackingArea.y2 += height - pScreen->height; 714 xf86RandR13VerifyPanningArea(crtc, width, height); 715 xf86RandR13Pan(crtc, randrp->pointerX, randrp->pointerY); 716 } 717 } 718 719 pScrnPix = (*pScreen->GetScreenPixmap) (pScreen); 720 pScreen->width = pScrnPix->drawable.width = width; 721 pScreen->height = pScrnPix->drawable.height = height; 722 randrp->mmWidth = pScreen->mmWidth = mmWidth; 723 randrp->mmHeight = pScreen->mmHeight = mmHeight; 724 725 xf86SetViewport(pScreen, pScreen->width - 1, pScreen->height - 1); 726 xf86SetViewport(pScreen, 0, 0); 727 728 finish: 729 update_desktop_dimensions(); 730 731 if (pRoot && pScrn->vtSema) 732 (*pScrn->EnableDisableFBAccess) (pScrn, TRUE); 733 #if RANDR_12_INTERFACE 734 if (pScreen->root && ret) 735 RRScreenSizeNotify(pScreen); 736 #endif 737 return ret; 738 } 739 740 Rotation 741 xf86RandR12GetRotation(ScreenPtr pScreen) 742 { 743 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 744 745 return randrp->rotation; 746 } 747 748 Bool 749 xf86RandR12CreateScreenResources(ScreenPtr pScreen) 750 { 751 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 752 xf86CrtcConfigPtr config; 753 XF86RandRInfoPtr randrp; 754 int c; 755 int width, height; 756 int mmWidth, mmHeight; 757 758 #ifdef PANORAMIX 759 /* XXX disable RandR when using Xinerama */ 760 if (!noPanoramiXExtension) 761 return TRUE; 762 #endif 763 764 config = XF86_CRTC_CONFIG_PTR(pScrn); 765 randrp = XF86RANDRINFO(pScreen); 766 /* 767 * Compute size of screen 768 */ 769 width = 0; 770 height = 0; 771 for (c = 0; c < config->num_crtc; c++) { 772 xf86CrtcPtr crtc = config->crtc[c]; 773 int crtc_width = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 774 int crtc_height = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 775 776 if (crtc->enabled) { 777 if (crtc_width > width) 778 width = crtc_width; 779 if (crtc_height > height) 780 height = crtc_height; 781 if (crtc->panningTotalArea.x2 > width) 782 width = crtc->panningTotalArea.x2; 783 if (crtc->panningTotalArea.y2 > height) 784 height = crtc->panningTotalArea.y2; 785 } 786 } 787 788 if (width && height) { 789 /* 790 * Compute physical size of screen 791 */ 792 if (monitorResolution) { 793 mmWidth = width * 25.4 / monitorResolution; 794 mmHeight = height * 25.4 / monitorResolution; 795 } 796 else { 797 xf86OutputPtr output = xf86CompatOutput(pScrn); 798 799 if (output && 800 output->conf_monitor && 801 (output->conf_monitor->mon_width > 0 && 802 output->conf_monitor->mon_height > 0)) { 803 /* 804 * Prefer user configured DisplaySize 805 */ 806 mmWidth = output->conf_monitor->mon_width; 807 mmHeight = output->conf_monitor->mon_height; 808 } 809 else { 810 /* 811 * Otherwise, just set the screen to DEFAULT_DPI 812 */ 813 mmWidth = width * 25.4 / DEFAULT_DPI; 814 mmHeight = height * 25.4 / DEFAULT_DPI; 815 } 816 } 817 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 818 "Setting screen physical size to %d x %d\n", 819 mmWidth, mmHeight); 820 /* 821 * This is the initial setting of the screen size. 822 * We have to pre-set it here, otherwise panning would be adapted 823 * to the new screen size. 824 */ 825 pScreen->width = width; 826 pScreen->height = height; 827 xf86RandR12ScreenSetSize(pScreen, width, height, mmWidth, mmHeight); 828 } 829 830 if (randrp->virtualX == -1 || randrp->virtualY == -1) { 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 Bool 843 xf86RandR12Init(ScreenPtr pScreen) 844 { 845 rrScrPrivPtr rp; 846 XF86RandRInfoPtr randrp; 847 848 #ifdef PANORAMIX 849 /* XXX disable RandR when using Xinerama */ 850 if (!noPanoramiXExtension) { 851 if (xf86NumScreens == 1) 852 noPanoramiXExtension = TRUE; 853 else 854 return TRUE; 855 } 856 #endif 857 858 if (xf86RandR12Generation != serverGeneration) 859 xf86RandR12Generation = serverGeneration; 860 861 if (!dixRegisterPrivateKey(&xf86RandR12KeyRec, PRIVATE_SCREEN, 0)) 862 return FALSE; 863 864 randrp = malloc(sizeof(XF86RandRInfoRec)); 865 if (!randrp) 866 return FALSE; 867 868 if (!RRScreenInit(pScreen)) { 869 free(randrp); 870 return FALSE; 871 } 872 rp = rrGetScrPriv(pScreen); 873 rp->rrGetInfo = xf86RandR12GetInfo; 874 rp->rrSetConfig = xf86RandR12SetConfig; 875 876 randrp->virtualX = -1; 877 randrp->virtualY = -1; 878 randrp->mmWidth = pScreen->mmWidth; 879 randrp->mmHeight = pScreen->mmHeight; 880 881 randrp->rotation = RR_Rotate_0; /* initial rotated mode */ 882 883 randrp->supported_rotations = RR_Rotate_0; 884 885 randrp->maxX = randrp->maxY = 0; 886 887 randrp->palette_size = 0; 888 randrp->palette = NULL; 889 890 dixSetPrivate(&pScreen->devPrivates, &xf86RandR12KeyRec, randrp); 891 892 #if RANDR_12_INTERFACE 893 if (!xf86RandR12Init12(pScreen)) 894 return FALSE; 895 #endif 896 return TRUE; 897 } 898 899 void 900 xf86RandR12CloseScreen(ScreenPtr pScreen) 901 { 902 XF86RandRInfoPtr randrp; 903 904 if (!dixPrivateKeyRegistered(&xf86RandR12KeyRec)) 905 return; 906 907 randrp = XF86RANDRINFO(pScreen); 908 #if RANDR_12_INTERFACE 909 xf86ScreenToScrn(pScreen)->EnterVT = randrp->orig_EnterVT; 910 pScreen->ConstrainCursorHarder = randrp->orig_ConstrainCursorHarder; 911 #endif 912 913 free(randrp->palette); 914 free(randrp); 915 } 916 917 void 918 xf86RandR12SetRotations(ScreenPtr pScreen, Rotation rotations) 919 { 920 XF86RandRInfoPtr randrp; 921 922 #if RANDR_12_INTERFACE 923 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 924 int c; 925 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 926 #endif 927 928 if (!dixPrivateKeyRegistered(&xf86RandR12KeyRec)) 929 return; 930 931 randrp = XF86RANDRINFO(pScreen); 932 #if RANDR_12_INTERFACE 933 for (c = 0; c < config->num_crtc; c++) { 934 xf86CrtcPtr crtc = config->crtc[c]; 935 936 RRCrtcSetRotations(crtc->randr_crtc, rotations); 937 } 938 #endif 939 randrp->supported_rotations = rotations; 940 } 941 942 void 943 xf86RandR12SetTransformSupport(ScreenPtr pScreen, Bool transforms) 944 { 945 #if RANDR_13_INTERFACE 946 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 947 int c; 948 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 949 950 if (!dixPrivateKeyRegistered(&xf86RandR12KeyRec)) 951 return; 952 953 for (c = 0; c < config->num_crtc; c++) { 954 xf86CrtcPtr crtc = config->crtc[c]; 955 956 RRCrtcSetTransformSupport(crtc->randr_crtc, transforms); 957 } 958 #endif 959 } 960 961 void 962 xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) 963 { 964 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 965 966 if (xf86RandR12Generation != serverGeneration || 967 XF86RANDRINFO(pScreen)->virtualX == -1) { 968 *x = pScrn->virtualX; 969 *y = pScrn->virtualY; 970 } 971 else { 972 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 973 974 *x = randrp->virtualX; 975 *y = randrp->virtualY; 976 } 977 } 978 979 #if RANDR_12_INTERFACE 980 981 #define FLAG_BITS (RR_HSyncPositive | \ 982 RR_HSyncNegative | \ 983 RR_VSyncPositive | \ 984 RR_VSyncNegative | \ 985 RR_Interlace | \ 986 RR_DoubleScan | \ 987 RR_CSync | \ 988 RR_CSyncPositive | \ 989 RR_CSyncNegative | \ 990 RR_HSkewPresent | \ 991 RR_BCast | \ 992 RR_PixelMultiplex | \ 993 RR_DoubleClock | \ 994 RR_ClockDivideBy2) 995 996 static Bool 997 xf86RandRModeMatches(RRModePtr randr_mode, DisplayModePtr mode) 998 { 999 #if 0 1000 if (match_name) { 1001 /* check for same name */ 1002 int len = strlen(mode->name); 1003 1004 if (randr_mode->mode.nameLength != len) 1005 return FALSE; 1006 if (memcmp(randr_mode->name, mode->name, len) != 0) 1007 return FALSE; 1008 } 1009 #endif 1010 1011 /* check for same timings */ 1012 if (randr_mode->mode.dotClock / 1000 != mode->Clock) 1013 return FALSE; 1014 if (randr_mode->mode.width != mode->HDisplay) 1015 return FALSE; 1016 if (randr_mode->mode.hSyncStart != mode->HSyncStart) 1017 return FALSE; 1018 if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) 1019 return FALSE; 1020 if (randr_mode->mode.hTotal != mode->HTotal) 1021 return FALSE; 1022 if (randr_mode->mode.hSkew != mode->HSkew) 1023 return FALSE; 1024 if (randr_mode->mode.height != mode->VDisplay) 1025 return FALSE; 1026 if (randr_mode->mode.vSyncStart != mode->VSyncStart) 1027 return FALSE; 1028 if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) 1029 return FALSE; 1030 if (randr_mode->mode.vTotal != mode->VTotal) 1031 return FALSE; 1032 1033 /* check for same flags (using only the XF86 valid flag bits) */ 1034 if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) 1035 return FALSE; 1036 1037 /* everything matches */ 1038 return TRUE; 1039 } 1040 1041 static Bool 1042 xf86RandR12CrtcNotify(RRCrtcPtr randr_crtc) 1043 { 1044 ScreenPtr pScreen = randr_crtc->pScreen; 1045 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1046 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1047 RRModePtr randr_mode = NULL; 1048 int x; 1049 int y; 1050 Rotation rotation; 1051 int numOutputs; 1052 RROutputPtr *randr_outputs; 1053 RROutputPtr randr_output; 1054 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1055 xf86OutputPtr output; 1056 int i, j; 1057 DisplayModePtr mode = &crtc->mode; 1058 Bool ret; 1059 1060 randr_outputs = xallocarray(config->num_output, sizeof(RROutputPtr)); 1061 if (!randr_outputs) 1062 return FALSE; 1063 x = crtc->x; 1064 y = crtc->y; 1065 rotation = crtc->rotation; 1066 numOutputs = 0; 1067 randr_mode = NULL; 1068 for (i = 0; i < config->num_output; i++) { 1069 output = config->output[i]; 1070 if (output->crtc == crtc) { 1071 randr_output = output->randr_output; 1072 randr_outputs[numOutputs++] = randr_output; 1073 /* 1074 * We make copies of modes, so pointer equality 1075 * isn't sufficient 1076 */ 1077 for (j = 0; j < randr_output->numModes + randr_output->numUserModes; 1078 j++) { 1079 RRModePtr m = 1080 (j < 1081 randr_output->numModes ? randr_output-> 1082 modes[j] : randr_output->userModes[j - 1083 randr_output-> 1084 numModes]); 1085 1086 if (xf86RandRModeMatches(m, mode)) { 1087 randr_mode = m; 1088 break; 1089 } 1090 } 1091 } 1092 } 1093 ret = RRCrtcNotify(randr_crtc, randr_mode, x, y, 1094 rotation, 1095 crtc->transformPresent ? &crtc->transform : NULL, 1096 numOutputs, randr_outputs); 1097 free(randr_outputs); 1098 return ret; 1099 } 1100 1101 /* 1102 * Convert a RandR mode to a DisplayMode 1103 */ 1104 static void 1105 xf86RandRModeConvert(ScrnInfoPtr scrn, 1106 RRModePtr randr_mode, DisplayModePtr mode) 1107 { 1108 memset(mode, 0, sizeof(DisplayModeRec)); 1109 mode->status = MODE_OK; 1110 1111 mode->Clock = randr_mode->mode.dotClock / 1000; 1112 1113 mode->HDisplay = randr_mode->mode.width; 1114 mode->HSyncStart = randr_mode->mode.hSyncStart; 1115 mode->HSyncEnd = randr_mode->mode.hSyncEnd; 1116 mode->HTotal = randr_mode->mode.hTotal; 1117 mode->HSkew = randr_mode->mode.hSkew; 1118 1119 mode->VDisplay = randr_mode->mode.height; 1120 mode->VSyncStart = randr_mode->mode.vSyncStart; 1121 mode->VSyncEnd = randr_mode->mode.vSyncEnd; 1122 mode->VTotal = randr_mode->mode.vTotal; 1123 mode->VScan = 0; 1124 1125 mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; 1126 1127 xf86SetModeCrtc(mode, scrn->adjustFlags); 1128 } 1129 1130 static Bool 1131 xf86RandR12CrtcSet(ScreenPtr pScreen, 1132 RRCrtcPtr randr_crtc, 1133 RRModePtr randr_mode, 1134 int x, 1135 int y, 1136 Rotation rotation, 1137 int num_randr_outputs, RROutputPtr * randr_outputs) 1138 { 1139 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1140 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1141 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1142 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1143 RRTransformPtr transform; 1144 Bool changed = FALSE; 1145 int o, ro; 1146 xf86CrtcPtr *save_crtcs; 1147 Bool save_enabled = crtc->enabled; 1148 1149 if (!crtc->scrn->vtSema) 1150 return FALSE; 1151 1152 save_crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr)); 1153 if ((randr_mode != NULL) != crtc->enabled) 1154 changed = TRUE; 1155 else if (randr_mode && !xf86RandRModeMatches(randr_mode, &crtc->mode)) 1156 changed = TRUE; 1157 1158 if (rotation != crtc->rotation) 1159 changed = TRUE; 1160 1161 if (crtc->current_scanout != randr_crtc->scanout_pixmap || 1162 crtc->current_scanout_back != randr_crtc->scanout_pixmap_back) 1163 changed = TRUE; 1164 1165 transform = RRCrtcGetTransform(randr_crtc); 1166 if ((transform != NULL) != crtc->transformPresent) 1167 changed = TRUE; 1168 else if (transform && 1169 !RRTransformEqual(transform, &crtc->transform)) 1170 changed = TRUE; 1171 1172 if (x != crtc->x || y != crtc->y) 1173 changed = TRUE; 1174 for (o = 0; o < config->num_output; o++) { 1175 xf86OutputPtr output = config->output[o]; 1176 xf86CrtcPtr new_crtc; 1177 1178 save_crtcs[o] = output->crtc; 1179 1180 if (output->crtc == crtc) 1181 new_crtc = NULL; 1182 else 1183 new_crtc = output->crtc; 1184 for (ro = 0; ro < num_randr_outputs; ro++) 1185 if (output->randr_output == randr_outputs[ro]) { 1186 new_crtc = crtc; 1187 break; 1188 } 1189 if (new_crtc != output->crtc) { 1190 changed = TRUE; 1191 output->crtc = new_crtc; 1192 } 1193 } 1194 for (ro = 0; ro < num_randr_outputs; ro++) 1195 if (randr_outputs[ro]->pendingProperties) 1196 changed = TRUE; 1197 1198 /* XXX need device-independent mode setting code through an API */ 1199 if (changed) { 1200 crtc->enabled = randr_mode != NULL; 1201 1202 if (randr_mode) { 1203 DisplayModeRec mode; 1204 1205 xf86RandRModeConvert(pScrn, randr_mode, &mode); 1206 if (!xf86CrtcSetModeTransform 1207 (crtc, &mode, rotation, transform, x, y)) { 1208 crtc->enabled = save_enabled; 1209 for (o = 0; o < config->num_output; o++) { 1210 xf86OutputPtr output = config->output[o]; 1211 1212 output->crtc = save_crtcs[o]; 1213 } 1214 free(save_crtcs); 1215 return FALSE; 1216 } 1217 xf86RandR13VerifyPanningArea(crtc, pScreen->width, pScreen->height); 1218 xf86RandR13Pan(crtc, randrp->pointerX, randrp->pointerY); 1219 randrp->panning = PANNING_ENABLED (crtc); 1220 /* 1221 * Save the last successful setting for EnterVT 1222 */ 1223 xf86SaveModeContents(&crtc->desiredMode, &mode); 1224 crtc->desiredRotation = rotation; 1225 crtc->current_scanout = randr_crtc->scanout_pixmap; 1226 crtc->current_scanout_back = randr_crtc->scanout_pixmap_back; 1227 if (transform) { 1228 crtc->desiredTransform = *transform; 1229 crtc->desiredTransformPresent = TRUE; 1230 } 1231 else 1232 crtc->desiredTransformPresent = FALSE; 1233 1234 crtc->desiredX = x; 1235 crtc->desiredY = y; 1236 } 1237 xf86DisableUnusedFunctions(pScrn); 1238 } 1239 free(save_crtcs); 1240 return xf86RandR12CrtcNotify(randr_crtc); 1241 } 1242 1243 static void 1244 xf86RandR12CrtcComputeGamma(xf86CrtcPtr crtc, LOCO *palette, 1245 int palette_red_size, int palette_green_size, 1246 int palette_blue_size, CARD16 *gamma_red, 1247 CARD16 *gamma_green, CARD16 *gamma_blue, 1248 int gamma_size) 1249 { 1250 int gamma_slots; 1251 unsigned shift; 1252 int i, j; 1253 CARD32 value = 0; 1254 1255 for (shift = 0; (gamma_size << shift) < (1 << 16); shift++); 1256 1257 if (crtc->gamma_size >= palette_red_size) { 1258 /* Upsampling of smaller palette to larger hw lut size */ 1259 gamma_slots = crtc->gamma_size / palette_red_size; 1260 for (i = 0; i < palette_red_size; i++) { 1261 value = palette[i].red; 1262 if (gamma_red) 1263 value = gamma_red[value]; 1264 else 1265 value <<= shift; 1266 1267 for (j = 0; j < gamma_slots; j++) 1268 crtc->gamma_red[i * gamma_slots + j] = value; 1269 } 1270 1271 /* Replicate last value until end of crtc for gamma_size not a power of 2 */ 1272 for (j = i * gamma_slots; j < crtc->gamma_size; j++) 1273 crtc->gamma_red[j] = value; 1274 } else { 1275 /* Downsampling of larger palette to smaller hw lut size */ 1276 for (i = 0; i < crtc->gamma_size; i++) { 1277 value = palette[i * (palette_red_size - 1) / (crtc->gamma_size - 1)].red; 1278 if (gamma_red) 1279 value = gamma_red[value]; 1280 else 1281 value <<= shift; 1282 1283 crtc->gamma_red[i] = value; 1284 } 1285 } 1286 1287 if (crtc->gamma_size >= palette_green_size) { 1288 /* Upsampling of smaller palette to larger hw lut size */ 1289 gamma_slots = crtc->gamma_size / palette_green_size; 1290 for (i = 0; i < palette_green_size; i++) { 1291 value = palette[i].green; 1292 if (gamma_green) 1293 value = gamma_green[value]; 1294 else 1295 value <<= shift; 1296 1297 for (j = 0; j < gamma_slots; j++) 1298 crtc->gamma_green[i * gamma_slots + j] = value; 1299 } 1300 1301 /* Replicate last value until end of crtc for gamma_size not a power of 2 */ 1302 for (j = i * gamma_slots; j < crtc->gamma_size; j++) 1303 crtc->gamma_green[j] = value; 1304 } else { 1305 /* Downsampling of larger palette to smaller hw lut size */ 1306 for (i = 0; i < crtc->gamma_size; i++) { 1307 value = palette[i * (palette_green_size - 1) / (crtc->gamma_size - 1)].green; 1308 if (gamma_green) 1309 value = gamma_green[value]; 1310 else 1311 value <<= shift; 1312 1313 crtc->gamma_green[i] = value; 1314 } 1315 } 1316 1317 if (crtc->gamma_size >= palette_blue_size) { 1318 /* Upsampling of smaller palette to larger hw lut size */ 1319 gamma_slots = crtc->gamma_size / palette_blue_size; 1320 for (i = 0; i < palette_blue_size; i++) { 1321 value = palette[i].blue; 1322 if (gamma_blue) 1323 value = gamma_blue[value]; 1324 else 1325 value <<= shift; 1326 1327 for (j = 0; j < gamma_slots; j++) 1328 crtc->gamma_blue[i * gamma_slots + j] = value; 1329 } 1330 1331 /* Replicate last value until end of crtc for gamma_size not a power of 2 */ 1332 for (j = i * gamma_slots; j < crtc->gamma_size; j++) 1333 crtc->gamma_blue[j] = value; 1334 } else { 1335 /* Downsampling of larger palette to smaller hw lut size */ 1336 for (i = 0; i < crtc->gamma_size; i++) { 1337 value = palette[i * (palette_blue_size - 1) / (crtc->gamma_size - 1)].blue; 1338 if (gamma_blue) 1339 value = gamma_blue[value]; 1340 else 1341 value <<= shift; 1342 1343 crtc->gamma_blue[i] = value; 1344 } 1345 } 1346 } 1347 1348 static void 1349 xf86RandR12CrtcReloadGamma(xf86CrtcPtr crtc) 1350 { 1351 if (!crtc->scrn->vtSema || !crtc->funcs->gamma_set) 1352 return; 1353 1354 /* Only set it when the crtc is actually running. 1355 * Otherwise it will be set when it's activated. 1356 */ 1357 if (crtc->active) 1358 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 1359 crtc->gamma_blue, crtc->gamma_size); 1360 } 1361 1362 static Bool 1363 xf86RandR12CrtcSetGamma(ScreenPtr pScreen, RRCrtcPtr randr_crtc) 1364 { 1365 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1366 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1367 int max_size = crtc->gamma_size; 1368 1369 if (crtc->funcs->gamma_set == NULL) 1370 return FALSE; 1371 1372 if (randrp->palette_size) { 1373 xf86RandR12CrtcComputeGamma(crtc, randrp->palette, 1374 randrp->palette_red_size, 1375 randrp->palette_green_size, 1376 randrp->palette_blue_size, 1377 randr_crtc->gammaRed, 1378 randr_crtc->gammaGreen, 1379 randr_crtc->gammaBlue, 1380 randr_crtc->gammaSize); 1381 } else { 1382 if (max_size > randr_crtc->gammaSize) 1383 max_size = randr_crtc->gammaSize; 1384 1385 memcpy(crtc->gamma_red, randr_crtc->gammaRed, 1386 max_size * sizeof(crtc->gamma_red[0])); 1387 memcpy(crtc->gamma_green, randr_crtc->gammaGreen, 1388 max_size * sizeof(crtc->gamma_green[0])); 1389 memcpy(crtc->gamma_blue, randr_crtc->gammaBlue, 1390 max_size * sizeof(crtc->gamma_blue[0])); 1391 } 1392 1393 xf86RandR12CrtcReloadGamma(crtc); 1394 1395 return TRUE; 1396 } 1397 1398 static void 1399 init_one_component(CARD16 *comp, unsigned size, float gamma) 1400 { 1401 int i; 1402 unsigned shift; 1403 1404 for (shift = 0; (size << shift) < (1 << 16); shift++); 1405 1406 if (gamma == 1.0) { 1407 for (i = 0; i < size; i++) 1408 comp[i] = i << shift; 1409 } else { 1410 for (i = 0; i < size; i++) 1411 comp[i] = (CARD16) (pow((double) i / (double) (size - 1), 1412 1. / (double) gamma) * 1413 (double) (size - 1) * (1 << shift)); 1414 } 1415 } 1416 1417 static Bool 1418 xf86RandR12CrtcInitGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, 1419 float gamma_blue) 1420 { 1421 unsigned size = crtc->randr_crtc->gammaSize; 1422 CARD16 *red, *green, *blue; 1423 1424 if (!crtc->funcs->gamma_set && 1425 (gamma_red != 1.0f || gamma_green != 1.0f || gamma_blue != 1.0f)) 1426 return FALSE; 1427 1428 red = xallocarray(size, 3 * sizeof(CARD16)); 1429 if (!red) 1430 return FALSE; 1431 1432 green = red + size; 1433 blue = green + size; 1434 1435 init_one_component(red, size, gamma_red); 1436 init_one_component(green, size, gamma_green); 1437 init_one_component(blue, size, gamma_blue); 1438 1439 RRCrtcGammaSet(crtc->randr_crtc, red, green, blue); 1440 free(red); 1441 1442 return TRUE; 1443 } 1444 1445 static Bool 1446 xf86RandR12OutputInitGamma(xf86OutputPtr output) 1447 { 1448 XF86ConfMonitorPtr mon = output->conf_monitor; 1449 float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; 1450 1451 if (!mon) 1452 return TRUE; 1453 1454 /* Get configured values, where they exist. */ 1455 if (mon->mon_gamma_red >= GAMMA_MIN && mon->mon_gamma_red <= GAMMA_MAX) 1456 gamma_red = mon->mon_gamma_red; 1457 1458 if (mon->mon_gamma_green >= GAMMA_MIN && mon->mon_gamma_green <= GAMMA_MAX) 1459 gamma_green = mon->mon_gamma_green; 1460 1461 if (mon->mon_gamma_blue >= GAMMA_MIN && mon->mon_gamma_blue <= GAMMA_MAX) 1462 gamma_blue = mon->mon_gamma_blue; 1463 1464 /* Don't set gamma 1.0 if another cloned output on this CRTC already set a 1465 * different gamma 1466 */ 1467 if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { 1468 if (!output->crtc->randr_crtc) { 1469 xf86DrvMsg(output->scrn->scrnIndex, X_WARNING, 1470 "Gamma correction for output %s not possible because " 1471 "RandR is disabled\n", output->name); 1472 return TRUE; 1473 } 1474 1475 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 1476 "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", 1477 output->name, gamma_red, gamma_green, gamma_blue); 1478 return xf86RandR12CrtcInitGamma(output->crtc, gamma_red, gamma_green, 1479 gamma_blue); 1480 } 1481 1482 return TRUE; 1483 } 1484 1485 Bool 1486 xf86RandR12InitGamma(ScrnInfoPtr pScrn, unsigned gammaSize) { 1487 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1488 int o, c; 1489 1490 /* Set default gamma for all CRTCs 1491 * This is done to avoid problems later on with cloned outputs 1492 */ 1493 for (c = 0; c < config->num_crtc; c++) { 1494 xf86CrtcPtr crtc = config->crtc[c]; 1495 1496 if (!crtc->randr_crtc) 1497 continue; 1498 1499 if (!RRCrtcGammaSetSize(crtc->randr_crtc, gammaSize) || 1500 !xf86RandR12CrtcInitGamma(crtc, 1.0f, 1.0f, 1.0f)) 1501 return FALSE; 1502 } 1503 1504 /* Set initial gamma per monitor configuration 1505 */ 1506 for (o = 0; o < config->num_output; o++) { 1507 xf86OutputPtr output = config->output[o]; 1508 1509 if (output->crtc && 1510 !xf86RandR12OutputInitGamma(output)) 1511 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1512 "Initial gamma correction for output %s: failed.\n", 1513 output->name); 1514 } 1515 1516 return TRUE; 1517 } 1518 1519 static Bool 1520 xf86RandR12OutputSetProperty(ScreenPtr pScreen, 1521 RROutputPtr randr_output, 1522 Atom property, RRPropertyValuePtr value) 1523 { 1524 xf86OutputPtr output = randr_output->devPrivate; 1525 1526 /* If we don't have any property handler, then we don't care what the 1527 * user is setting properties to. 1528 */ 1529 if (output->funcs->set_property == NULL) 1530 return TRUE; 1531 1532 /* 1533 * This function gets called even when vtSema is FALSE, as 1534 * drivers will need to remember the correct value to apply 1535 * when the VT switch occurs 1536 */ 1537 return output->funcs->set_property(output, property, value); 1538 } 1539 1540 static Bool 1541 xf86RandR13OutputGetProperty(ScreenPtr pScreen, 1542 RROutputPtr randr_output, Atom property) 1543 { 1544 xf86OutputPtr output = randr_output->devPrivate; 1545 1546 if (output->funcs->get_property == NULL) 1547 return TRUE; 1548 1549 /* Should be safe even w/o vtSema */ 1550 return output->funcs->get_property(output, property); 1551 } 1552 1553 static Bool 1554 xf86RandR12OutputValidateMode(ScreenPtr pScreen, 1555 RROutputPtr randr_output, RRModePtr randr_mode) 1556 { 1557 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1558 xf86OutputPtr output = randr_output->devPrivate; 1559 DisplayModeRec mode; 1560 1561 xf86RandRModeConvert(pScrn, randr_mode, &mode); 1562 /* 1563 * This function may be called when vtSema is FALSE, so 1564 * the underlying function must either avoid touching the hardware 1565 * or return FALSE when vtSema is FALSE 1566 */ 1567 if (output->funcs->mode_valid(output, &mode) != MODE_OK) 1568 return FALSE; 1569 return TRUE; 1570 } 1571 1572 static void 1573 xf86RandR12ModeDestroy(ScreenPtr pScreen, RRModePtr randr_mode) 1574 { 1575 } 1576 1577 /** 1578 * Given a list of xf86 modes and a RandR Output object, construct 1579 * RandR modes and assign them to the output 1580 */ 1581 static Bool 1582 xf86RROutputSetModes(RROutputPtr randr_output, DisplayModePtr modes) 1583 { 1584 DisplayModePtr mode; 1585 RRModePtr *rrmodes = NULL; 1586 int nmode = 0; 1587 int npreferred = 0; 1588 Bool ret = TRUE; 1589 int pref; 1590 1591 for (mode = modes; mode; mode = mode->next) 1592 nmode++; 1593 1594 if (nmode) { 1595 rrmodes = xallocarray(nmode, sizeof(RRModePtr)); 1596 1597 if (!rrmodes) 1598 return FALSE; 1599 nmode = 0; 1600 1601 for (pref = 1; pref >= 0; pref--) { 1602 for (mode = modes; mode; mode = mode->next) { 1603 if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { 1604 xRRModeInfo modeInfo; 1605 RRModePtr rrmode; 1606 1607 modeInfo.nameLength = strlen(mode->name); 1608 modeInfo.width = mode->HDisplay; 1609 modeInfo.dotClock = mode->Clock * 1000; 1610 modeInfo.hSyncStart = mode->HSyncStart; 1611 modeInfo.hSyncEnd = mode->HSyncEnd; 1612 modeInfo.hTotal = mode->HTotal; 1613 modeInfo.hSkew = mode->HSkew; 1614 1615 modeInfo.height = mode->VDisplay; 1616 modeInfo.vSyncStart = mode->VSyncStart; 1617 modeInfo.vSyncEnd = mode->VSyncEnd; 1618 modeInfo.vTotal = mode->VTotal; 1619 modeInfo.modeFlags = mode->Flags; 1620 1621 rrmode = RRModeGet(&modeInfo, mode->name); 1622 if (rrmode) { 1623 rrmodes[nmode++] = rrmode; 1624 npreferred += pref; 1625 } 1626 } 1627 } 1628 } 1629 } 1630 1631 ret = RROutputSetModes(randr_output, rrmodes, nmode, npreferred); 1632 free(rrmodes); 1633 return ret; 1634 } 1635 1636 /* 1637 * Mirror the current mode configuration to RandR 1638 */ 1639 static Bool 1640 xf86RandR12SetInfo12(ScreenPtr pScreen) 1641 { 1642 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1643 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1644 RROutputPtr *clones; 1645 RRCrtcPtr *crtcs; 1646 int ncrtc; 1647 int o, c, l; 1648 int nclone; 1649 1650 clones = xallocarray(config->num_output, sizeof(RROutputPtr)); 1651 crtcs = xallocarray(config->num_crtc, sizeof(RRCrtcPtr)); 1652 for (o = 0; o < config->num_output; o++) { 1653 xf86OutputPtr output = config->output[o]; 1654 1655 ncrtc = 0; 1656 for (c = 0; c < config->num_crtc; c++) 1657 if (output->possible_crtcs & (1 << c)) 1658 crtcs[ncrtc++] = config->crtc[c]->randr_crtc; 1659 1660 if (!RROutputSetCrtcs(output->randr_output, crtcs, ncrtc)) { 1661 free(crtcs); 1662 free(clones); 1663 return FALSE; 1664 } 1665 1666 RROutputSetPhysicalSize(output->randr_output, 1667 output->mm_width, output->mm_height); 1668 xf86RROutputSetModes(output->randr_output, output->probed_modes); 1669 1670 switch (output->status) { 1671 case XF86OutputStatusConnected: 1672 RROutputSetConnection(output->randr_output, RR_Connected); 1673 break; 1674 case XF86OutputStatusDisconnected: 1675 if (xf86OutputForceEnabled(output)) 1676 RROutputSetConnection(output->randr_output, RR_Connected); 1677 else 1678 RROutputSetConnection(output->randr_output, RR_Disconnected); 1679 break; 1680 case XF86OutputStatusUnknown: 1681 RROutputSetConnection(output->randr_output, RR_UnknownConnection); 1682 break; 1683 } 1684 1685 RROutputSetSubpixelOrder(output->randr_output, output->subpixel_order); 1686 1687 /* 1688 * Valid clones 1689 */ 1690 nclone = 0; 1691 for (l = 0; l < config->num_output; l++) { 1692 xf86OutputPtr clone = config->output[l]; 1693 1694 if (l != o && (output->possible_clones & (1 << l))) 1695 clones[nclone++] = clone->randr_output; 1696 } 1697 if (!RROutputSetClones(output->randr_output, clones, nclone)) { 1698 free(crtcs); 1699 free(clones); 1700 return FALSE; 1701 } 1702 } 1703 free(crtcs); 1704 free(clones); 1705 return TRUE; 1706 } 1707 1708 /* 1709 * Query the hardware for the current state, then mirror 1710 * that to RandR 1711 */ 1712 static Bool 1713 xf86RandR12GetInfo12(ScreenPtr pScreen, Rotation * rotations) 1714 { 1715 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1716 1717 if (!pScrn->vtSema) 1718 return TRUE; 1719 xf86ProbeOutputModes(pScrn, 0, 0); 1720 xf86SetScrnInfoModes(pScrn); 1721 return xf86RandR12SetInfo12(pScreen); 1722 } 1723 1724 static Bool 1725 xf86RandR12CreateObjects12(ScreenPtr pScreen) 1726 { 1727 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1728 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1729 int c; 1730 int o; 1731 1732 if (!RRInit()) 1733 return FALSE; 1734 1735 /* 1736 * Configure crtcs 1737 */ 1738 for (c = 0; c < config->num_crtc; c++) { 1739 xf86CrtcPtr crtc = config->crtc[c]; 1740 1741 crtc->randr_crtc = RRCrtcCreate(pScreen, crtc); 1742 } 1743 /* 1744 * Configure outputs 1745 */ 1746 for (o = 0; o < config->num_output; o++) { 1747 xf86OutputPtr output = config->output[o]; 1748 1749 output->randr_output = RROutputCreate(pScreen, output->name, 1750 strlen(output->name), output); 1751 1752 if (output->funcs->create_resources != NULL) 1753 output->funcs->create_resources(output); 1754 RRPostPendingProperties(output->randr_output); 1755 } 1756 1757 if (config->name) { 1758 config->randr_provider = RRProviderCreate(pScreen, config->name, 1759 strlen(config->name)); 1760 1761 RRProviderSetCapabilities(config->randr_provider, pScrn->capabilities); 1762 } 1763 1764 return TRUE; 1765 } 1766 1767 static void 1768 xf86RandR12CreateMonitors(ScreenPtr pScreen) 1769 { 1770 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1771 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1772 int o, ot; 1773 int ht, vt; 1774 int ret; 1775 char buf[25]; 1776 1777 for (o = 0; o < config->num_output; o++) { 1778 xf86OutputPtr output = config->output[o]; 1779 struct xf86CrtcTileInfo *tile_info = &output->tile_info, *this_tile; 1780 RRMonitorPtr monitor; 1781 int output_num, num_outputs; 1782 if (!tile_info->group_id) 1783 continue; 1784 1785 if (tile_info->tile_h_loc || 1786 tile_info->tile_v_loc) 1787 continue; 1788 1789 num_outputs = tile_info->num_h_tile * tile_info->num_v_tile; 1790 1791 monitor = RRMonitorAlloc(num_outputs); 1792 if (!monitor) 1793 return; 1794 monitor->pScreen = pScreen; 1795 snprintf(buf, 25, "Auto-Monitor-%d", tile_info->group_id); 1796 monitor->name = MakeAtom(buf, strlen(buf), TRUE); 1797 monitor->primary = 0; 1798 monitor->automatic = TRUE; 1799 memset(&monitor->geometry.box, 0, sizeof(monitor->geometry.box)); 1800 1801 output_num = 0; 1802 for (ht = 0; ht < tile_info->num_h_tile; ht++) { 1803 for (vt = 0; vt < tile_info->num_v_tile; vt++) { 1804 1805 for (ot = 0; ot < config->num_output; ot++) { 1806 this_tile = &config->output[ot]->tile_info; 1807 1808 if (this_tile->group_id != tile_info->group_id) 1809 continue; 1810 1811 if (this_tile->tile_h_loc != ht || 1812 this_tile->tile_v_loc != vt) 1813 continue; 1814 1815 monitor->outputs[output_num] = config->output[ot]->randr_output->id; 1816 output_num++; 1817 1818 } 1819 1820 } 1821 } 1822 1823 ret = RRMonitorAdd(serverClient, pScreen, monitor); 1824 if (ret) { 1825 RRMonitorFree(monitor); 1826 return; 1827 } 1828 } 1829 } 1830 1831 static Bool 1832 xf86RandR12CreateScreenResources12(ScreenPtr pScreen) 1833 { 1834 int c; 1835 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1836 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 1837 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1838 1839 for (c = 0; c < config->num_crtc; c++) 1840 xf86RandR12CrtcNotify(config->crtc[c]->randr_crtc); 1841 1842 RRScreenSetSizeRange(pScreen, config->minWidth, config->minHeight, 1843 config->maxWidth, config->maxHeight); 1844 1845 xf86RandR12CreateMonitors(pScreen); 1846 1847 if (!pScreen->isGPU) { 1848 rp->primaryOutput = config->output[0]->randr_output; 1849 RROutputChanged(rp->primaryOutput, FALSE); 1850 rp->layoutChanged = TRUE; 1851 } 1852 1853 return TRUE; 1854 } 1855 1856 /* 1857 * Something happened within the screen configuration due 1858 * to DGA, VidMode or hot key. Tell RandR 1859 */ 1860 1861 void 1862 xf86RandR12TellChanged(ScreenPtr pScreen) 1863 { 1864 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1865 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1866 int c; 1867 1868 xf86RandR12SetInfo12(pScreen); 1869 for (c = 0; c < config->num_crtc; c++) 1870 xf86RandR12CrtcNotify(config->crtc[c]->randr_crtc); 1871 1872 RRTellChanged(pScreen); 1873 } 1874 1875 static void 1876 xf86RandR12PointerMoved(ScrnInfoPtr pScrn, int x, int y) 1877 { 1878 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 1879 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1880 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1881 int c; 1882 1883 randrp->pointerX = x; 1884 randrp->pointerY = y; 1885 for (c = 0; c < config->num_crtc; c++) 1886 xf86RandR13Pan(config->crtc[c], x, y); 1887 } 1888 1889 static Bool 1890 xf86RandR13GetPanning(ScreenPtr pScreen, 1891 RRCrtcPtr randr_crtc, 1892 BoxPtr totalArea, BoxPtr trackingArea, INT16 *border) 1893 { 1894 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1895 1896 if (crtc->version < 2) 1897 return FALSE; 1898 if (totalArea) 1899 memcpy(totalArea, &crtc->panningTotalArea, sizeof(BoxRec)); 1900 if (trackingArea) 1901 memcpy(trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); 1902 if (border) 1903 memcpy(border, crtc->panningBorder, 4 * sizeof(INT16)); 1904 1905 return TRUE; 1906 } 1907 1908 static Bool 1909 xf86RandR13SetPanning(ScreenPtr pScreen, 1910 RRCrtcPtr randr_crtc, 1911 BoxPtr totalArea, BoxPtr trackingArea, INT16 *border) 1912 { 1913 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1914 xf86CrtcPtr crtc = randr_crtc->devPrivate; 1915 BoxRec oldTotalArea; 1916 BoxRec oldTrackingArea; 1917 INT16 oldBorder[4]; 1918 Bool oldPanning = randrp->panning; 1919 1920 if (crtc->version < 2) 1921 return FALSE; 1922 1923 memcpy(&oldTotalArea, &crtc->panningTotalArea, sizeof(BoxRec)); 1924 memcpy(&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec)); 1925 memcpy(oldBorder, crtc->panningBorder, 4 * sizeof(INT16)); 1926 1927 if (totalArea) 1928 memcpy(&crtc->panningTotalArea, totalArea, sizeof(BoxRec)); 1929 if (trackingArea) 1930 memcpy(&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec)); 1931 if (border) 1932 memcpy(crtc->panningBorder, border, 4 * sizeof(INT16)); 1933 1934 if (xf86RandR13VerifyPanningArea(crtc, pScreen->width, pScreen->height)) { 1935 xf86RandR13Pan(crtc, randrp->pointerX, randrp->pointerY); 1936 randrp->panning = PANNING_ENABLED (crtc); 1937 return TRUE; 1938 } 1939 else { 1940 /* Restore old settings */ 1941 memcpy(&crtc->panningTotalArea, &oldTotalArea, sizeof(BoxRec)); 1942 memcpy(&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec)); 1943 memcpy(crtc->panningBorder, oldBorder, 4 * sizeof(INT16)); 1944 randrp->panning = oldPanning; 1945 return FALSE; 1946 } 1947 } 1948 1949 /* 1950 * Compatibility with colormaps and XF86VidMode's gamma 1951 */ 1952 void 1953 xf86RandR12LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, 1954 LOCO *colors, VisualPtr pVisual) 1955 { 1956 ScreenPtr pScreen = pScrn->pScreen; 1957 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1958 int reds, greens, blues, index, palette_size; 1959 int c, i; 1960 1961 if (pVisual->class == TrueColor || pVisual->class == DirectColor) { 1962 reds = (pVisual->redMask >> pVisual->offsetRed) + 1; 1963 greens = (pVisual->greenMask >> pVisual->offsetGreen) + 1; 1964 blues = (pVisual->blueMask >> pVisual->offsetBlue) + 1; 1965 } else { 1966 reds = greens = blues = pVisual->ColormapEntries; 1967 } 1968 1969 palette_size = max(reds, max(greens, blues)); 1970 1971 if (dixPrivateKeyRegistered(rrPrivKey)) { 1972 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 1973 1974 if (randrp->palette_size != palette_size) { 1975 randrp->palette = reallocarray(randrp->palette, palette_size, 1976 sizeof(colors[0])); 1977 if (!randrp->palette) { 1978 randrp->palette_size = 0; 1979 return; 1980 } 1981 1982 randrp->palette_size = palette_size; 1983 } 1984 randrp->palette_red_size = reds; 1985 randrp->palette_green_size = greens; 1986 randrp->palette_blue_size = blues; 1987 1988 for (i = 0; i < numColors; i++) { 1989 index = indices[i]; 1990 1991 if (index < reds) 1992 randrp->palette[index].red = colors[index].red; 1993 if (index < greens) 1994 randrp->palette[index].green = colors[index].green; 1995 if (index < blues) 1996 randrp->palette[index].blue = colors[index].blue; 1997 } 1998 } 1999 2000 for (c = 0; c < config->num_crtc; c++) { 2001 xf86CrtcPtr crtc = config->crtc[c]; 2002 RRCrtcPtr randr_crtc = crtc->randr_crtc; 2003 2004 if (randr_crtc) { 2005 xf86RandR12CrtcComputeGamma(crtc, colors, reds, greens, blues, 2006 randr_crtc->gammaRed, 2007 randr_crtc->gammaGreen, 2008 randr_crtc->gammaBlue, 2009 randr_crtc->gammaSize); 2010 } else { 2011 xf86RandR12CrtcComputeGamma(crtc, colors, reds, greens, blues, 2012 NULL, NULL, NULL, 2013 xf86GetGammaRampSize(pScreen)); 2014 } 2015 xf86RandR12CrtcReloadGamma(crtc); 2016 } 2017 } 2018 2019 /* 2020 * Compatibility pScrn->ChangeGamma provider for ddx drivers which do not call 2021 * xf86HandleColormaps(). Note such drivers really should be fixed to call 2022 * xf86HandleColormaps() as this clobbers the per-CRTC gamma ramp of the CRTC 2023 * assigned to the RandR compatibility output. 2024 */ 2025 static int 2026 xf86RandR12ChangeGamma(ScrnInfoPtr pScrn, Gamma gamma) 2027 { 2028 RRCrtcPtr randr_crtc = xf86CompatRRCrtc(pScrn); 2029 int size; 2030 2031 if (!randr_crtc || pScrn->LoadPalette == xf86RandR12LoadPalette) 2032 return Success; 2033 2034 size = max(0, randr_crtc->gammaSize); 2035 if (!size) 2036 return Success; 2037 2038 init_one_component(randr_crtc->gammaRed, size, gamma.red); 2039 init_one_component(randr_crtc->gammaGreen, size, gamma.green); 2040 init_one_component(randr_crtc->gammaBlue, size, gamma.blue); 2041 xf86RandR12CrtcSetGamma(xf86ScrnToScreen(pScrn), randr_crtc); 2042 2043 pScrn->gamma = gamma; 2044 2045 return Success; 2046 } 2047 2048 static Bool 2049 xf86RandR12EnterVT(ScrnInfoPtr pScrn) 2050 { 2051 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 2052 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 2053 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 2054 Bool ret; 2055 int i; 2056 2057 if (randrp->orig_EnterVT) { 2058 pScrn->EnterVT = randrp->orig_EnterVT; 2059 ret = pScrn->EnterVT(pScrn); 2060 randrp->orig_EnterVT = pScrn->EnterVT; 2061 pScrn->EnterVT = xf86RandR12EnterVT; 2062 if (!ret) 2063 return FALSE; 2064 } 2065 2066 /* reload gamma */ 2067 for (i = 0; i < rp->numCrtcs; i++) 2068 xf86RandR12CrtcReloadGamma(rp->crtcs[i]->devPrivate); 2069 2070 return RRGetInfo(pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */ 2071 } 2072 2073 static void 2074 xf86DetachOutputGPU(ScreenPtr pScreen) 2075 { 2076 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 2077 int i; 2078 2079 /* make sure there are no attached shared scanout pixmaps first */ 2080 for (i = 0; i < rp->numCrtcs; i++) 2081 RRCrtcDetachScanoutPixmap(rp->crtcs[i]); 2082 2083 DetachOutputGPU(pScreen); 2084 } 2085 2086 static Bool 2087 xf86RandR14ProviderSetOutputSource(ScreenPtr pScreen, 2088 RRProviderPtr provider, 2089 RRProviderPtr source_provider) 2090 { 2091 if (!source_provider) { 2092 if (provider->output_source) { 2093 xf86DetachOutputGPU(pScreen); 2094 } 2095 provider->output_source = NULL; 2096 return TRUE; 2097 } 2098 2099 if (provider->output_source == source_provider) 2100 return TRUE; 2101 2102 SetRootClip(source_provider->pScreen, ROOT_CLIP_NONE); 2103 2104 AttachOutputGPU(source_provider->pScreen, pScreen); 2105 2106 provider->output_source = source_provider; 2107 SetRootClip(source_provider->pScreen, ROOT_CLIP_FULL); 2108 return TRUE; 2109 } 2110 2111 static Bool 2112 xf86RandR14ProviderSetOffloadSink(ScreenPtr pScreen, 2113 RRProviderPtr provider, 2114 RRProviderPtr sink_provider) 2115 { 2116 if (!sink_provider) { 2117 if (provider->offload_sink) { 2118 xf86DetachOutputGPU(pScreen); 2119 } 2120 2121 provider->offload_sink = NULL; 2122 return TRUE; 2123 } 2124 2125 if (provider->offload_sink == sink_provider) 2126 return TRUE; 2127 2128 AttachOffloadGPU(sink_provider->pScreen, pScreen); 2129 2130 provider->offload_sink = sink_provider; 2131 return TRUE; 2132 } 2133 2134 static Bool 2135 xf86RandR14ProviderSetProperty(ScreenPtr pScreen, 2136 RRProviderPtr randr_provider, 2137 Atom property, RRPropertyValuePtr value) 2138 { 2139 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2140 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2141 2142 /* If we don't have any property handler, then we don't care what the 2143 * user is setting properties to. 2144 */ 2145 if (config->provider_funcs->set_property == NULL) 2146 return TRUE; 2147 2148 /* 2149 * This function gets called even when vtSema is FALSE, as 2150 * drivers will need to remember the correct value to apply 2151 * when the VT switch occurs 2152 */ 2153 return config->provider_funcs->set_property(pScrn, property, value); 2154 } 2155 2156 static Bool 2157 xf86RandR14ProviderGetProperty(ScreenPtr pScreen, 2158 RRProviderPtr randr_provider, Atom property) 2159 { 2160 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2161 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2162 2163 if (config->provider_funcs->get_property == NULL) 2164 return TRUE; 2165 2166 /* Should be safe even w/o vtSema */ 2167 return config->provider_funcs->get_property(pScrn, property); 2168 } 2169 2170 static Bool 2171 xf86CrtcSetScanoutPixmap(RRCrtcPtr randr_crtc, PixmapPtr pixmap) 2172 { 2173 xf86CrtcPtr crtc = randr_crtc->devPrivate; 2174 if (!crtc->funcs->set_scanout_pixmap) 2175 return FALSE; 2176 return crtc->funcs->set_scanout_pixmap(crtc, pixmap); 2177 } 2178 2179 static void 2180 xf86RandR13ConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y) 2181 { 2182 XF86RandRInfoPtr randrp = XF86RANDRINFO(screen); 2183 2184 if (randrp->panning) 2185 return; 2186 2187 if (randrp->orig_ConstrainCursorHarder) { 2188 screen->ConstrainCursorHarder = randrp->orig_ConstrainCursorHarder; 2189 screen->ConstrainCursorHarder(dev, screen, mode, x, y); 2190 screen->ConstrainCursorHarder = xf86RandR13ConstrainCursorHarder; 2191 } 2192 } 2193 2194 static void 2195 xf86RandR14ProviderDestroy(ScreenPtr screen, RRProviderPtr provider) 2196 { 2197 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2198 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2199 2200 if (config->randr_provider == provider) { 2201 if (config->randr_provider->offload_sink) { 2202 DetachOffloadGPU(screen); 2203 config->randr_provider->offload_sink = NULL; 2204 RRSetChanged(screen); 2205 } 2206 if (config->randr_provider->output_source) { 2207 xf86DetachOutputGPU(screen); 2208 config->randr_provider->output_source = NULL; 2209 RRSetChanged(screen); 2210 } 2211 if (screen->current_primary) 2212 DetachUnboundGPU(screen); 2213 } 2214 config->randr_provider = NULL; 2215 } 2216 2217 static void 2218 xf86CrtcCheckReset(xf86CrtcPtr crtc) { 2219 if (xf86CrtcInUse(crtc)) { 2220 RRTransformPtr transform; 2221 2222 if (crtc->desiredTransformPresent) 2223 transform = &crtc->desiredTransform; 2224 else 2225 transform = NULL; 2226 xf86CrtcSetModeTransform(crtc, &crtc->desiredMode, 2227 crtc->desiredRotation, transform, 2228 crtc->desiredX, crtc->desiredY); 2229 xf86_crtc_show_cursor(crtc); 2230 } 2231 } 2232 2233 void 2234 xf86CrtcLeaseTerminated(RRLeasePtr lease) 2235 { 2236 int c; 2237 int o; 2238 ScrnInfoPtr scrn = xf86ScreenToScrn(lease->screen); 2239 2240 RRLeaseTerminated(lease); 2241 /* 2242 * Force a full mode set on any crtc in the expiring lease which 2243 * was running before the lease started 2244 */ 2245 for (c = 0; c < lease->numCrtcs; c++) { 2246 RRCrtcPtr randr_crtc = lease->crtcs[c]; 2247 xf86CrtcPtr crtc = randr_crtc->devPrivate; 2248 2249 xf86CrtcCheckReset(crtc); 2250 } 2251 2252 /* Check to see if any leased output is using a crtc which 2253 * was not reset in the above loop 2254 */ 2255 for (o = 0; o < lease->numOutputs; o++) { 2256 RROutputPtr randr_output = lease->outputs[o]; 2257 xf86OutputPtr output = randr_output->devPrivate; 2258 xf86CrtcPtr crtc = output->crtc; 2259 2260 if (crtc) { 2261 for (c = 0; c < lease->numCrtcs; c++) 2262 if (lease->crtcs[c] == crtc->randr_crtc) 2263 break; 2264 if (c != lease->numCrtcs) 2265 continue; 2266 xf86CrtcCheckReset(crtc); 2267 } 2268 } 2269 2270 /* Power off if necessary */ 2271 xf86DisableUnusedFunctions(scrn); 2272 2273 RRLeaseFree(lease); 2274 } 2275 2276 static Bool 2277 xf86CrtcSoleOutput(xf86CrtcPtr crtc, xf86OutputPtr output) 2278 { 2279 ScrnInfoPtr scrn = crtc->scrn; 2280 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2281 int o; 2282 2283 for (o = 0; o < config->num_output; o++) { 2284 xf86OutputPtr other = config->output[o]; 2285 2286 if (other != output && other->crtc == crtc) 2287 return FALSE; 2288 } 2289 return TRUE; 2290 } 2291 2292 void 2293 xf86CrtcLeaseStarted(RRLeasePtr lease) 2294 { 2295 int c; 2296 int o; 2297 2298 for (c = 0; c < lease->numCrtcs; c++) { 2299 RRCrtcPtr randr_crtc = lease->crtcs[c]; 2300 xf86CrtcPtr crtc = randr_crtc->devPrivate; 2301 2302 if (crtc->enabled) { 2303 /* 2304 * Leave the primary plane enabled so we can 2305 * flip without blanking the screen. Hide 2306 * the cursor so it doesn't remain on the screen 2307 * while the lease is active 2308 */ 2309 xf86_crtc_hide_cursor(crtc); 2310 crtc->enabled = FALSE; 2311 } 2312 } 2313 for (o = 0; o < lease->numOutputs; o++) { 2314 RROutputPtr randr_output = lease->outputs[o]; 2315 xf86OutputPtr output = randr_output->devPrivate; 2316 xf86CrtcPtr crtc = output->crtc; 2317 2318 if (crtc) 2319 if (xf86CrtcSoleOutput(crtc, output)) 2320 crtc->enabled = FALSE; 2321 } 2322 } 2323 2324 static int 2325 xf86RandR16CreateLease(ScreenPtr screen, RRLeasePtr randr_lease, int *fd) 2326 { 2327 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2328 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2329 2330 if (config->funcs->create_lease) 2331 return config->funcs->create_lease(randr_lease, fd); 2332 else 2333 return BadMatch; 2334 } 2335 2336 2337 static void 2338 xf86RandR16TerminateLease(ScreenPtr screen, RRLeasePtr randr_lease) 2339 { 2340 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2341 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2342 2343 if (config->funcs->terminate_lease) 2344 config->funcs->terminate_lease(randr_lease); 2345 } 2346 2347 static Bool 2348 xf86RandR12Init12(ScreenPtr pScreen) 2349 { 2350 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 2351 rrScrPrivPtr rp = rrGetScrPriv(pScreen); 2352 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); 2353 2354 rp->rrGetInfo = xf86RandR12GetInfo12; 2355 rp->rrScreenSetSize = xf86RandR12ScreenSetSize; 2356 rp->rrCrtcSet = xf86RandR12CrtcSet; 2357 rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; 2358 rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; 2359 rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; 2360 #if RANDR_13_INTERFACE 2361 rp->rrOutputGetProperty = xf86RandR13OutputGetProperty; 2362 rp->rrGetPanning = xf86RandR13GetPanning; 2363 rp->rrSetPanning = xf86RandR13SetPanning; 2364 #endif 2365 rp->rrModeDestroy = xf86RandR12ModeDestroy; 2366 rp->rrSetConfig = NULL; 2367 2368 rp->rrProviderSetOutputSource = xf86RandR14ProviderSetOutputSource; 2369 rp->rrProviderSetOffloadSink = xf86RandR14ProviderSetOffloadSink; 2370 2371 rp->rrProviderSetProperty = xf86RandR14ProviderSetProperty; 2372 rp->rrProviderGetProperty = xf86RandR14ProviderGetProperty; 2373 rp->rrCrtcSetScanoutPixmap = xf86CrtcSetScanoutPixmap; 2374 rp->rrProviderDestroy = xf86RandR14ProviderDestroy; 2375 2376 rp->rrCreateLease = xf86RandR16CreateLease; 2377 rp->rrTerminateLease = xf86RandR16TerminateLease; 2378 2379 pScrn->PointerMoved = xf86RandR12PointerMoved; 2380 pScrn->ChangeGamma = xf86RandR12ChangeGamma; 2381 2382 randrp->orig_EnterVT = pScrn->EnterVT; 2383 pScrn->EnterVT = xf86RandR12EnterVT; 2384 2385 randrp->panning = FALSE; 2386 randrp->orig_ConstrainCursorHarder = pScreen->ConstrainCursorHarder; 2387 pScreen->ConstrainCursorHarder = xf86RandR13ConstrainCursorHarder; 2388 2389 if (!xf86RandR12CreateObjects12(pScreen)) 2390 return FALSE; 2391 2392 /* 2393 * Configure output modes 2394 */ 2395 if (!xf86RandR12SetInfo12(pScreen)) 2396 return FALSE; 2397 2398 if (!xf86RandR12InitGamma(pScrn, 256)) 2399 return FALSE; 2400 2401 return TRUE; 2402 } 2403 2404 #endif 2405 2406 Bool 2407 xf86RandR12PreInit(ScrnInfoPtr pScrn) 2408 { 2409 return TRUE; 2410 }