xf86Crtc.c revision 35c4bbdf
1/* 2 * Copyright © 2006 Keith Packard 3 * Copyright © 2008 Red Hat, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_XORG_CONFIG_H 25#include <xorg-config.h> 26#else 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30#endif 31 32#include <stddef.h> 33#include <string.h> 34#include <stdio.h> 35 36#include "xf86.h" 37#include "xf86DDC.h" 38#include "xf86Crtc.h" 39#include "xf86Modes.h" 40#include "xf86Priv.h" 41#include "xf86RandR12.h" 42#include "X11/extensions/render.h" 43#include "X11/extensions/dpmsconst.h" 44#include "X11/Xatom.h" 45#include "picturestr.h" 46 47#ifdef XV 48#include "xf86xv.h" 49#endif 50 51#define NO_OUTPUT_DEFAULT_WIDTH 1024 52#define NO_OUTPUT_DEFAULT_HEIGHT 768 53/* 54 * Initialize xf86CrtcConfig structure 55 */ 56 57int xf86CrtcConfigPrivateIndex = -1; 58 59void 60xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs) 61{ 62 xf86CrtcConfigPtr config; 63 64 if (xf86CrtcConfigPrivateIndex == -1) 65 xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); 66 config = xnfcalloc(1, sizeof(xf86CrtcConfigRec)); 67 68 config->funcs = funcs; 69 config->compat_output = -1; 70 71 scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; 72} 73 74void 75xf86CrtcSetSizeRange(ScrnInfoPtr scrn, 76 int minWidth, int minHeight, int maxWidth, int maxHeight) 77{ 78 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 79 80 config->minWidth = minWidth; 81 config->minHeight = minHeight; 82 config->maxWidth = maxWidth; 83 config->maxHeight = maxHeight; 84} 85 86/* 87 * Crtc functions 88 */ 89xf86CrtcPtr 90xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs) 91{ 92 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 93 xf86CrtcPtr crtc, *crtcs; 94 95 crtc = calloc(sizeof(xf86CrtcRec), 1); 96 if (!crtc) 97 return NULL; 98 crtc->version = XF86_CRTC_VERSION; 99 crtc->scrn = scrn; 100 crtc->funcs = funcs; 101#ifdef RANDR_12_INTERFACE 102 crtc->randr_crtc = NULL; 103#endif 104 crtc->rotation = RR_Rotate_0; 105 crtc->desiredRotation = RR_Rotate_0; 106 pixman_transform_init_identity(&crtc->crtc_to_framebuffer); 107 pixman_f_transform_init_identity(&crtc->f_crtc_to_framebuffer); 108 pixman_f_transform_init_identity(&crtc->f_framebuffer_to_crtc); 109 crtc->filter = NULL; 110 crtc->params = NULL; 111 crtc->nparams = 0; 112 crtc->filter_width = 0; 113 crtc->filter_height = 0; 114 crtc->transform_in_use = FALSE; 115 crtc->transformPresent = FALSE; 116 crtc->desiredTransformPresent = FALSE; 117 memset(&crtc->bounds, '\0', sizeof(crtc->bounds)); 118 119 /* Preallocate gamma at a sensible size. */ 120 crtc->gamma_size = 256; 121 crtc->gamma_red = xallocarray(crtc->gamma_size, 3 * sizeof(CARD16)); 122 if (!crtc->gamma_red) { 123 free(crtc); 124 return NULL; 125 } 126 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 127 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 128 129 if (xf86_config->crtc) 130 crtcs = reallocarray(xf86_config->crtc, 131 xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr)); 132 else 133 crtcs = xallocarray(xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr)); 134 if (!crtcs) { 135 free(crtc->gamma_red); 136 free(crtc); 137 return NULL; 138 } 139 xf86_config->crtc = crtcs; 140 xf86_config->crtc[xf86_config->num_crtc++] = crtc; 141 return crtc; 142} 143 144void 145xf86CrtcDestroy(xf86CrtcPtr crtc) 146{ 147 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 148 int c; 149 150 (*crtc->funcs->destroy) (crtc); 151 for (c = 0; c < xf86_config->num_crtc; c++) 152 if (xf86_config->crtc[c] == crtc) { 153 memmove(&xf86_config->crtc[c], 154 &xf86_config->crtc[c + 1], 155 ((xf86_config->num_crtc - (c + 1)) * sizeof(void *))); 156 xf86_config->num_crtc--; 157 break; 158 } 159 free(crtc->params); 160 free(crtc->gamma_red); 161 free(crtc); 162} 163 164/** 165 * Return whether any outputs are connected to the specified pipe 166 */ 167 168Bool 169xf86CrtcInUse(xf86CrtcPtr crtc) 170{ 171 ScrnInfoPtr pScrn = crtc->scrn; 172 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 173 int o; 174 175 for (o = 0; o < xf86_config->num_output; o++) 176 if (xf86_config->output[o]->crtc == crtc) 177 return TRUE; 178 return FALSE; 179} 180 181void 182xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen) 183{ 184 int subpixel_order = SubPixelUnknown; 185 Bool has_none = FALSE; 186 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 187 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 188 int icrtc, o; 189 190 for (icrtc = 0; icrtc < xf86_config->num_crtc; icrtc++) { 191 xf86CrtcPtr crtc = xf86_config->crtc[icrtc]; 192 193 for (o = 0; o < xf86_config->num_output; o++) { 194 xf86OutputPtr output = xf86_config->output[o]; 195 196 if (output->crtc == crtc) { 197 switch (output->subpixel_order) { 198 case SubPixelNone: 199 has_none = TRUE; 200 break; 201 case SubPixelUnknown: 202 break; 203 default: 204 subpixel_order = output->subpixel_order; 205 break; 206 } 207 } 208 if (subpixel_order != SubPixelUnknown) 209 break; 210 } 211 if (subpixel_order != SubPixelUnknown) { 212 static const int circle[4] = { 213 SubPixelHorizontalRGB, 214 SubPixelVerticalRGB, 215 SubPixelHorizontalBGR, 216 SubPixelVerticalBGR, 217 }; 218 int rotate; 219 int sc; 220 221 for (rotate = 0; rotate < 4; rotate++) 222 if (crtc->rotation & (1 << rotate)) 223 break; 224 for (sc = 0; sc < 4; sc++) 225 if (circle[sc] == subpixel_order) 226 break; 227 sc = (sc + rotate) & 0x3; 228 if ((crtc->rotation & RR_Reflect_X) && !(sc & 1)) 229 sc ^= 2; 230 if ((crtc->rotation & RR_Reflect_Y) && (sc & 1)) 231 sc ^= 2; 232 subpixel_order = circle[sc]; 233 break; 234 } 235 } 236 if (subpixel_order == SubPixelUnknown && has_none) 237 subpixel_order = SubPixelNone; 238 PictureSetSubpixelOrder(pScreen, subpixel_order); 239} 240 241/** 242 * Sets the given video mode on the given crtc 243 */ 244Bool 245xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode, 246 Rotation rotation, RRTransformPtr transform, int x, 247 int y) 248{ 249 ScrnInfoPtr scrn = crtc->scrn; 250 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 251 int i; 252 Bool ret = FALSE; 253 Bool didLock = FALSE; 254 DisplayModePtr adjusted_mode; 255 DisplayModeRec saved_mode; 256 int saved_x, saved_y; 257 Rotation saved_rotation; 258 RRTransformRec saved_transform; 259 Bool saved_transform_present; 260 261 crtc->enabled = xf86CrtcInUse(crtc); 262 263 /* We only hit this if someone explicitly sends a "disabled" modeset. */ 264 if (!crtc->enabled) { 265 /* Check everything for stuff that should be off. */ 266 xf86DisableUnusedFunctions(scrn); 267 return TRUE; 268 } 269 270 adjusted_mode = xf86DuplicateMode(mode); 271 272 saved_mode = crtc->mode; 273 saved_x = crtc->x; 274 saved_y = crtc->y; 275 saved_rotation = crtc->rotation; 276 if (crtc->transformPresent) { 277 RRTransformInit(&saved_transform); 278 RRTransformCopy(&saved_transform, &crtc->transform); 279 } 280 saved_transform_present = crtc->transformPresent; 281 282 /* Update crtc values up front so the driver can rely on them for mode 283 * setting. 284 */ 285 crtc->mode = *mode; 286 crtc->x = x; 287 crtc->y = y; 288 crtc->rotation = rotation; 289 if (transform) { 290 RRTransformCopy(&crtc->transform, transform); 291 crtc->transformPresent = TRUE; 292 } 293 else 294 crtc->transformPresent = FALSE; 295 296 if (crtc->funcs->set_mode_major) { 297 ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y); 298 goto done; 299 } 300 301 didLock = crtc->funcs->lock(crtc); 302 /* Pass our mode to the outputs and the CRTC to give them a chance to 303 * adjust it according to limitations or output properties, and also 304 * a chance to reject the mode entirely. 305 */ 306 for (i = 0; i < xf86_config->num_output; i++) { 307 xf86OutputPtr output = xf86_config->output[i]; 308 309 if (output->crtc != crtc) 310 continue; 311 312 if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { 313 goto done; 314 } 315 } 316 317 if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { 318 goto done; 319 } 320 321 if (!xf86CrtcRotate(crtc)) 322 goto done; 323 324 /* Prepare the outputs and CRTCs before setting the mode. */ 325 for (i = 0; i < xf86_config->num_output; i++) { 326 xf86OutputPtr output = xf86_config->output[i]; 327 328 if (output->crtc != crtc) 329 continue; 330 331 /* Disable the output as the first thing we do. */ 332 output->funcs->prepare(output); 333 } 334 335 crtc->funcs->prepare(crtc); 336 337 /* Set up the DPLL and any output state that needs to adjust or depend 338 * on the DPLL. 339 */ 340 crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y); 341 for (i = 0; i < xf86_config->num_output; i++) { 342 xf86OutputPtr output = xf86_config->output[i]; 343 344 if (output->crtc == crtc) 345 output->funcs->mode_set(output, mode, adjusted_mode); 346 } 347 348 /* Only upload when needed, to avoid unneeded delays. */ 349 if (!crtc->active && crtc->funcs->gamma_set) 350 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 351 crtc->gamma_blue, crtc->gamma_size); 352 353 /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ 354 crtc->funcs->commit(crtc); 355 for (i = 0; i < xf86_config->num_output; i++) { 356 xf86OutputPtr output = xf86_config->output[i]; 357 358 if (output->crtc == crtc) 359 output->funcs->commit(output); 360 } 361 362 ret = TRUE; 363 364 done: 365 if (ret) { 366 crtc->active = TRUE; 367 if (scrn->pScreen) 368 xf86CrtcSetScreenSubpixelOrder(scrn->pScreen); 369 if (scrn->ModeSet) 370 scrn->ModeSet(scrn); 371 372 /* Make sure the HW cursor is hidden if it's supposed to be, in case 373 * it was hidden while the CRTC was disabled 374 */ 375 if (!xf86_config->cursor_on) 376 xf86_hide_cursors(scrn); 377 } 378 else { 379 crtc->x = saved_x; 380 crtc->y = saved_y; 381 crtc->rotation = saved_rotation; 382 crtc->mode = saved_mode; 383 if (saved_transform_present) 384 RRTransformCopy(&crtc->transform, &saved_transform); 385 crtc->transformPresent = saved_transform_present; 386 } 387 388 free((void *) adjusted_mode->name); 389 free(adjusted_mode); 390 391 if (didLock) 392 crtc->funcs->unlock(crtc); 393 394 return ret; 395} 396 397/** 398 * Sets the given video mode on the given crtc, but without providing 399 * a transform 400 */ 401Bool 402xf86CrtcSetMode(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, 403 int x, int y) 404{ 405 return xf86CrtcSetModeTransform(crtc, mode, rotation, NULL, x, y); 406} 407 408/** 409 * Pans the screen, does not change the mode 410 */ 411void 412xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y) 413{ 414 ScrnInfoPtr scrn = crtc->scrn; 415 416 crtc->x = x; 417 crtc->y = y; 418 if (crtc->funcs->set_origin) { 419 if (!xf86CrtcRotate(crtc)) 420 return; 421 crtc->funcs->set_origin(crtc, x, y); 422 if (scrn->ModeSet) 423 scrn->ModeSet(scrn); 424 } 425 else 426 xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, x, y); 427} 428 429/* 430 * Output functions 431 */ 432 433extern XF86ConfigPtr xf86configptr; 434 435typedef enum { 436 OPTION_PREFERRED_MODE, 437 OPTION_ZOOM_MODES, 438 OPTION_POSITION, 439 OPTION_BELOW, 440 OPTION_RIGHT_OF, 441 OPTION_ABOVE, 442 OPTION_LEFT_OF, 443 OPTION_ENABLE, 444 OPTION_DISABLE, 445 OPTION_MIN_CLOCK, 446 OPTION_MAX_CLOCK, 447 OPTION_IGNORE, 448 OPTION_ROTATE, 449 OPTION_PANNING, 450 OPTION_PRIMARY, 451 OPTION_DEFAULT_MODES, 452} OutputOpts; 453 454static OptionInfoRec xf86OutputOptions[] = { 455 {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE}, 456 {OPTION_ZOOM_MODES, "ZoomModes", OPTV_STRING, {0}, FALSE }, 457 {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE}, 458 {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE}, 459 {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE}, 460 {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE}, 461 {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE}, 462 {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE}, 463 {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE}, 464 {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE}, 465 {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE}, 466 {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE}, 467 {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE}, 468 {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE}, 469 {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE}, 470 {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE}, 471 {-1, NULL, OPTV_NONE, {0}, FALSE}, 472}; 473 474enum { 475 OPTION_MODEDEBUG, 476}; 477 478static OptionInfoRec xf86DeviceOptions[] = { 479 {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE}, 480 {-1, NULL, OPTV_NONE, {0}, FALSE}, 481}; 482 483static void 484xf86OutputSetMonitor(xf86OutputPtr output) 485{ 486 char *option_name; 487 const char *monitor; 488 489 if (!output->name) 490 return; 491 492 free(output->options); 493 494 output->options = xnfalloc(sizeof(xf86OutputOptions)); 495 memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions)); 496 497 XNFasprintf(&option_name, "monitor-%s", output->name); 498 monitor = xf86findOptionValue(output->scrn->options, option_name); 499 if (!monitor) 500 monitor = output->name; 501 else 502 xf86MarkOptionUsedByName(output->scrn->options, option_name); 503 free(option_name); 504 output->conf_monitor = xf86findMonitor(monitor, 505 xf86configptr->conf_monitor_lst); 506 /* 507 * Find the monitor section of the screen and use that 508 */ 509 if (!output->conf_monitor && output->use_screen_monitor) 510 output->conf_monitor = xf86findMonitor(output->scrn->monitor->id, 511 xf86configptr->conf_monitor_lst); 512 if (output->conf_monitor) { 513 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 514 "Output %s using monitor section %s\n", 515 output->name, output->conf_monitor->mon_identifier); 516 xf86ProcessOptions(output->scrn->scrnIndex, 517 output->conf_monitor->mon_option_lst, 518 output->options); 519 } 520 else 521 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 522 "Output %s has no monitor section\n", output->name); 523} 524 525static Bool 526xf86OutputEnabled(xf86OutputPtr output, Bool strict) 527{ 528 Bool enable, disable; 529 530 /* check to see if this output was enabled in the config file */ 531 if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable) { 532 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 533 "Output %s enabled by config file\n", output->name); 534 return TRUE; 535 } 536 /* or if this output was disabled in the config file */ 537 if (xf86GetOptValBool(output->options, OPTION_DISABLE, &disable) && disable) { 538 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 539 "Output %s disabled by config file\n", output->name); 540 return FALSE; 541 } 542 543 /* If not, try to only light up the ones we know are connected */ 544 if (strict) { 545 enable = output->status == XF86OutputStatusConnected; 546 } 547 /* But if that fails, try to light up even outputs we're unsure of */ 548 else { 549 enable = output->status != XF86OutputStatusDisconnected; 550 } 551 552 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 553 "Output %s %sconnected\n", output->name, enable ? "" : "dis"); 554 return enable; 555} 556 557static Bool 558xf86OutputIgnored(xf86OutputPtr output) 559{ 560 return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE); 561} 562 563static const char *direction[4] = { 564 "normal", 565 "left", 566 "inverted", 567 "right" 568}; 569 570static Rotation 571xf86OutputInitialRotation(xf86OutputPtr output) 572{ 573 const char *rotate_name = xf86GetOptValString(output->options, 574 OPTION_ROTATE); 575 int i; 576 577 if (!rotate_name) { 578 if (output->initial_rotation) 579 return output->initial_rotation; 580 return RR_Rotate_0; 581 } 582 583 for (i = 0; i < 4; i++) 584 if (xf86nameCompare(direction[i], rotate_name) == 0) 585 return 1 << i; 586 return RR_Rotate_0; 587} 588 589xf86OutputPtr 590xf86OutputCreate(ScrnInfoPtr scrn, 591 const xf86OutputFuncsRec * funcs, const char *name) 592{ 593 xf86OutputPtr output, *outputs; 594 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 595 int len; 596 Bool primary; 597 598 if (name) 599 len = strlen(name) + 1; 600 else 601 len = 0; 602 603 output = calloc(sizeof(xf86OutputRec) + len, 1); 604 if (!output) 605 return NULL; 606 output->scrn = scrn; 607 output->funcs = funcs; 608 if (name) { 609 output->name = (char *) (output + 1); 610 strcpy(output->name, name); 611 } 612 output->subpixel_order = SubPixelUnknown; 613 /* 614 * Use the old per-screen monitor section for the first output 615 */ 616 output->use_screen_monitor = (xf86_config->num_output == 0); 617#ifdef RANDR_12_INTERFACE 618 output->randr_output = NULL; 619#endif 620 if (name) { 621 xf86OutputSetMonitor(output); 622 if (xf86OutputIgnored(output)) { 623 free(output); 624 return FALSE; 625 } 626 } 627 628 if (xf86_config->output) 629 outputs = reallocarray(xf86_config->output, 630 xf86_config->num_output + 1, 631 sizeof(xf86OutputPtr)); 632 else 633 outputs = xallocarray(xf86_config->num_output + 1, 634 sizeof(xf86OutputPtr)); 635 if (!outputs) { 636 free(output); 637 return NULL; 638 } 639 640 xf86_config->output = outputs; 641 642 if (xf86GetOptValBool(output->options, OPTION_PRIMARY, &primary) && primary) { 643 memmove(xf86_config->output + 1, xf86_config->output, 644 xf86_config->num_output * sizeof(xf86OutputPtr)); 645 xf86_config->output[0] = output; 646 } 647 else { 648 xf86_config->output[xf86_config->num_output] = output; 649 } 650 651 xf86_config->num_output++; 652 653 return output; 654} 655 656Bool 657xf86OutputRename(xf86OutputPtr output, const char *name) 658{ 659 char *newname = strdup(name); 660 661 if (!newname) 662 return FALSE; /* so sorry... */ 663 664 if (output->name && output->name != (char *) (output + 1)) 665 free(output->name); 666 output->name = newname; 667 xf86OutputSetMonitor(output); 668 if (xf86OutputIgnored(output)) 669 return FALSE; 670 return TRUE; 671} 672 673void 674xf86OutputUseScreenMonitor(xf86OutputPtr output, Bool use_screen_monitor) 675{ 676 if (use_screen_monitor != output->use_screen_monitor) { 677 output->use_screen_monitor = use_screen_monitor; 678 xf86OutputSetMonitor(output); 679 } 680} 681 682void 683xf86OutputDestroy(xf86OutputPtr output) 684{ 685 ScrnInfoPtr scrn = output->scrn; 686 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 687 int o; 688 689 (*output->funcs->destroy) (output); 690 while (output->probed_modes) 691 xf86DeleteMode(&output->probed_modes, output->probed_modes); 692 for (o = 0; o < xf86_config->num_output; o++) 693 if (xf86_config->output[o] == output) { 694 memmove(&xf86_config->output[o], 695 &xf86_config->output[o + 1], 696 ((xf86_config->num_output - (o + 1)) * sizeof(void *))); 697 xf86_config->num_output--; 698 break; 699 } 700 if (output->name && output->name != (char *) (output + 1)) 701 free(output->name); 702 free(output); 703} 704 705/* 706 * Called during CreateScreenResources to hook up RandR 707 */ 708static Bool 709xf86CrtcCreateScreenResources(ScreenPtr screen) 710{ 711 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 712 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 713 714 screen->CreateScreenResources = config->CreateScreenResources; 715 716 if (!(*screen->CreateScreenResources) (screen)) 717 return FALSE; 718 719 if (!xf86RandR12CreateScreenResources(screen)) 720 return FALSE; 721 722 return TRUE; 723} 724 725/* 726 * Clean up config on server reset 727 */ 728static Bool 729xf86CrtcCloseScreen(ScreenPtr screen) 730{ 731 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 732 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 733 int o, c; 734 735 screen->CloseScreen = config->CloseScreen; 736 737 xf86RotateCloseScreen(screen); 738 739 xf86RandR12CloseScreen(screen); 740 741 screen->CloseScreen(screen); 742 743 for (o = 0; o < config->num_output; o++) { 744 xf86OutputPtr output = config->output[o]; 745 746 output->randr_output = NULL; 747 } 748 for (c = 0; c < config->num_crtc; c++) { 749 xf86CrtcPtr crtc = config->crtc[c]; 750 751 crtc->randr_crtc = NULL; 752 } 753 /* detach any providers */ 754 if (config->randr_provider) { 755 RRProviderDestroy(config->randr_provider); 756 config->randr_provider = NULL; 757 } 758 return TRUE; 759} 760 761/* 762 * Called at ScreenInit time to set up 763 */ 764#ifdef RANDR_13_INTERFACE 765int 766#else 767Bool 768#endif 769xf86CrtcScreenInit(ScreenPtr screen) 770{ 771 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 772 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 773 int c; 774 775 /* Rotation */ 776 xf86DrvMsg(scrn->scrnIndex, X_INFO, 777 "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); 778 xf86DisableRandR(); /* Disable old RandR extension support */ 779 xf86RandR12Init(screen); 780 781 /* support all rotations if every crtc has the shadow alloc funcs */ 782 for (c = 0; c < config->num_crtc; c++) { 783 xf86CrtcPtr crtc = config->crtc[c]; 784 785 if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) 786 break; 787 } 788 if (c == config->num_crtc) { 789 xf86RandR12SetRotations(screen, RR_Rotate_0 | RR_Rotate_90 | 790 RR_Rotate_180 | RR_Rotate_270 | 791 RR_Reflect_X | RR_Reflect_Y); 792 xf86RandR12SetTransformSupport(screen, TRUE); 793 } 794 else { 795 xf86RandR12SetRotations(screen, RR_Rotate_0); 796 xf86RandR12SetTransformSupport(screen, FALSE); 797 } 798 799 /* Wrap CreateScreenResources so we can initialize the RandR code */ 800 config->CreateScreenResources = screen->CreateScreenResources; 801 screen->CreateScreenResources = xf86CrtcCreateScreenResources; 802 803 config->CloseScreen = screen->CloseScreen; 804 screen->CloseScreen = xf86CrtcCloseScreen; 805 806 /* This might still be marked wrapped from a previous generation */ 807 config->BlockHandler = NULL; 808 809#ifdef XFreeXDGA 810 _xf86_di_dga_init_internal(screen); 811#endif 812#ifdef RANDR_13_INTERFACE 813 return RANDR_INTERFACE_VERSION; 814#else 815 return TRUE; 816#endif 817} 818 819static DisplayModePtr 820xf86DefaultMode(xf86OutputPtr output, int width, int height) 821{ 822 DisplayModePtr target_mode = NULL; 823 DisplayModePtr mode; 824 int target_diff = 0; 825 int target_preferred = 0; 826 int mm_height; 827 828 mm_height = output->mm_height; 829 if (!mm_height) 830 mm_height = (768 * 25.4) / DEFAULT_DPI; 831 /* 832 * Pick a mode closest to DEFAULT_DPI 833 */ 834 for (mode = output->probed_modes; mode; mode = mode->next) { 835 int dpi; 836 int preferred = (((mode->type & M_T_PREFERRED) != 0) + 837 ((mode->type & M_T_USERPREF) != 0)); 838 int diff; 839 840 if (xf86ModeWidth(mode, output->initial_rotation) > width || 841 xf86ModeHeight(mode, output->initial_rotation) > height) 842 continue; 843 844 /* yes, use VDisplay here, not xf86ModeHeight */ 845 dpi = (mode->VDisplay * 254) / (mm_height * 10); 846 diff = dpi - DEFAULT_DPI; 847 diff = diff < 0 ? -diff : diff; 848 if (target_mode == NULL || (preferred > target_preferred) || 849 (preferred == target_preferred && diff < target_diff)) { 850 target_mode = mode; 851 target_diff = diff; 852 target_preferred = preferred; 853 } 854 } 855 return target_mode; 856} 857 858static DisplayModePtr 859xf86ClosestMode(xf86OutputPtr output, 860 DisplayModePtr match, Rotation match_rotation, 861 int width, int height) 862{ 863 DisplayModePtr target_mode = NULL; 864 DisplayModePtr mode; 865 int target_diff = 0; 866 867 /* 868 * Pick a mode closest to the specified mode 869 */ 870 for (mode = output->probed_modes; mode; mode = mode->next) { 871 int dx, dy; 872 int diff; 873 874 if (xf86ModeWidth(mode, output->initial_rotation) > width || 875 xf86ModeHeight(mode, output->initial_rotation) > height) 876 continue; 877 878 /* exact matches are preferred */ 879 if (output->initial_rotation == match_rotation && 880 xf86ModesEqual(mode, match)) 881 return mode; 882 883 dx = xf86ModeWidth(match, match_rotation) - xf86ModeWidth(mode, 884 output-> 885 initial_rotation); 886 dy = xf86ModeHeight(match, match_rotation) - xf86ModeHeight(mode, 887 output-> 888 initial_rotation); 889 diff = dx * dx + dy * dy; 890 if (target_mode == NULL || diff < target_diff) { 891 target_mode = mode; 892 target_diff = diff; 893 } 894 } 895 return target_mode; 896} 897 898static DisplayModePtr 899xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height) 900{ 901 DisplayModePtr mode; 902 903 for (mode = output->probed_modes; mode; mode = mode->next) { 904 if (xf86ModeWidth(mode, output->initial_rotation) > width || 905 xf86ModeHeight(mode, output->initial_rotation) > height) 906 continue; 907 908 if (mode->type & M_T_PREFERRED) 909 return mode; 910 } 911 return NULL; 912} 913 914static DisplayModePtr 915xf86OutputHasUserPreferredMode(xf86OutputPtr output) 916{ 917 DisplayModePtr mode, first = output->probed_modes; 918 919 for (mode = first; mode && mode->next != first; mode = mode->next) 920 if (mode->type & M_T_USERPREF) 921 return mode; 922 923 return NULL; 924} 925 926static int 927xf86PickCrtcs(ScrnInfoPtr scrn, 928 xf86CrtcPtr * best_crtcs, 929 DisplayModePtr * modes, int n, int width, int height) 930{ 931 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 932 int c, o; 933 xf86OutputPtr output; 934 xf86CrtcPtr crtc; 935 xf86CrtcPtr *crtcs; 936 int best_score; 937 int score; 938 int my_score; 939 940 if (n == config->num_output) 941 return 0; 942 output = config->output[n]; 943 944 /* 945 * Compute score with this output disabled 946 */ 947 best_crtcs[n] = NULL; 948 best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height); 949 if (modes[n] == NULL) 950 return best_score; 951 952 crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr)); 953 if (!crtcs) 954 return best_score; 955 956 my_score = 1; 957 /* Score outputs that are known to be connected higher */ 958 if (output->status == XF86OutputStatusConnected) 959 my_score++; 960 /* Score outputs with preferred modes higher */ 961 if (xf86OutputHasPreferredMode(output, width, height)) 962 my_score++; 963 /* 964 * Select a crtc for this output and 965 * then attempt to configure the remaining 966 * outputs 967 */ 968 for (c = 0; c < config->num_crtc; c++) { 969 if ((output->possible_crtcs & (1 << c)) == 0) 970 continue; 971 972 crtc = config->crtc[c]; 973 /* 974 * Check to see if some other output is 975 * using this crtc 976 */ 977 for (o = 0; o < n; o++) 978 if (best_crtcs[o] == crtc) 979 break; 980 if (o < n) { 981 /* 982 * If the two outputs desire the same mode, 983 * see if they can be cloned 984 */ 985 if (xf86ModesEqual(modes[o], modes[n]) && 986 config->output[o]->initial_rotation == 987 config->output[n]->initial_rotation && 988 config->output[o]->initial_x == config->output[n]->initial_x && 989 config->output[o]->initial_y == config->output[n]->initial_y) { 990 if ((output->possible_clones & (1 << o)) == 0) 991 continue; /* nope, try next CRTC */ 992 } 993 else 994 continue; /* different modes, can't clone */ 995 } 996 crtcs[n] = crtc; 997 memcpy(crtcs, best_crtcs, n * sizeof(xf86CrtcPtr)); 998 score = 999 my_score + xf86PickCrtcs(scrn, crtcs, modes, n + 1, width, height); 1000 if (score > best_score) { 1001 best_score = score; 1002 memcpy(best_crtcs, crtcs, config->num_output * sizeof(xf86CrtcPtr)); 1003 } 1004 } 1005 free(crtcs); 1006 return best_score; 1007} 1008 1009/* 1010 * Compute the virtual size necessary to place all of the available 1011 * crtcs in the specified configuration. 1012 * 1013 * canGrow indicates that the driver can make the screen larger than its initial 1014 * configuration. If FALSE, this function will enlarge the screen to include 1015 * the largest available mode. 1016 */ 1017 1018static void 1019xf86DefaultScreenLimits(ScrnInfoPtr scrn, int *widthp, int *heightp, 1020 Bool canGrow) 1021{ 1022 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1023 int width = 0, height = 0; 1024 int o; 1025 int c; 1026 int s; 1027 1028 for (c = 0; c < config->num_crtc; c++) { 1029 int crtc_width = 0, crtc_height = 0; 1030 xf86CrtcPtr crtc = config->crtc[c]; 1031 1032 if (crtc->enabled) { 1033 crtc_width = 1034 crtc->desiredX + xf86ModeWidth(&crtc->desiredMode, 1035 crtc->desiredRotation); 1036 crtc_height = 1037 crtc->desiredY + xf86ModeHeight(&crtc->desiredMode, 1038 crtc->desiredRotation); 1039 } 1040 if (!canGrow) { 1041 for (o = 0; o < config->num_output; o++) { 1042 xf86OutputPtr output = config->output[o]; 1043 1044 for (s = 0; s < config->num_crtc; s++) 1045 if (output->possible_crtcs & (1 << s)) { 1046 DisplayModePtr mode; 1047 1048 for (mode = output->probed_modes; mode; 1049 mode = mode->next) { 1050 if (mode->HDisplay > crtc_width) 1051 crtc_width = mode->HDisplay; 1052 if (mode->VDisplay > crtc_width) 1053 crtc_width = mode->VDisplay; 1054 if (mode->VDisplay > crtc_height) 1055 crtc_height = mode->VDisplay; 1056 if (mode->HDisplay > crtc_height) 1057 crtc_height = mode->HDisplay; 1058 } 1059 } 1060 } 1061 } 1062 if (crtc_width > width) 1063 width = crtc_width; 1064 if (crtc_height > height) 1065 height = crtc_height; 1066 } 1067 if (config->maxWidth && width > config->maxWidth) 1068 width = config->maxWidth; 1069 if (config->maxHeight && height > config->maxHeight) 1070 height = config->maxHeight; 1071 if (config->minWidth && width < config->minWidth) 1072 width = config->minWidth; 1073 if (config->minHeight && height < config->minHeight) 1074 height = config->minHeight; 1075 *widthp = width; 1076 *heightp = height; 1077} 1078 1079#define POSITION_UNSET -100000 1080 1081/* 1082 * check if the user configured any outputs at all 1083 * with either a position or a relative setting or a mode. 1084 */ 1085static Bool 1086xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr * modes) 1087{ 1088 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1089 int o; 1090 Bool user_conf = FALSE; 1091 1092 for (o = 0; o < config->num_output; o++) { 1093 xf86OutputPtr output = config->output[o]; 1094 const char *position; 1095 const char *relative_name; 1096 OutputOpts relation; 1097 int r; 1098 1099 static const OutputOpts relations[] = { 1100 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1101 }; 1102 1103 position = xf86GetOptValString(output->options, OPTION_POSITION); 1104 if (position) 1105 user_conf = TRUE; 1106 1107 relation = 0; 1108 relative_name = NULL; 1109 for (r = 0; r < 4; r++) { 1110 relation = relations[r]; 1111 relative_name = xf86GetOptValString(output->options, relation); 1112 if (relative_name) 1113 break; 1114 } 1115 if (relative_name) 1116 user_conf = TRUE; 1117 1118 modes[o] = xf86OutputHasUserPreferredMode(output); 1119 if (modes[o]) 1120 user_conf = TRUE; 1121 } 1122 1123 return user_conf; 1124} 1125 1126static Bool 1127xf86InitialOutputPositions(ScrnInfoPtr scrn, DisplayModePtr * modes) 1128{ 1129 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1130 int o; 1131 int min_x, min_y; 1132 1133 /* check for initial right-of heuristic */ 1134 for (o = 0; o < config->num_output; o++) 1135 { 1136 xf86OutputPtr output = config->output[o]; 1137 1138 if (output->initial_x || output->initial_y) 1139 return TRUE; 1140 } 1141 1142 for (o = 0; o < config->num_output; o++) { 1143 xf86OutputPtr output = config->output[o]; 1144 1145 output->initial_x = output->initial_y = POSITION_UNSET; 1146 } 1147 1148 /* 1149 * Loop until all outputs are set 1150 */ 1151 for (;;) { 1152 Bool any_set = FALSE; 1153 Bool keep_going = FALSE; 1154 1155 for (o = 0; o < config->num_output; o++) { 1156 static const OutputOpts relations[] = { 1157 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1158 }; 1159 xf86OutputPtr output = config->output[o]; 1160 xf86OutputPtr relative; 1161 const char *relative_name; 1162 const char *position; 1163 OutputOpts relation; 1164 int r; 1165 1166 if (output->initial_x != POSITION_UNSET) 1167 continue; 1168 position = xf86GetOptValString(output->options, OPTION_POSITION); 1169 /* 1170 * Absolute position wins 1171 */ 1172 if (position) { 1173 int x, y; 1174 1175 if (sscanf(position, "%d %d", &x, &y) == 2) { 1176 output->initial_x = x; 1177 output->initial_y = y; 1178 } 1179 else { 1180 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1181 "Output %s position not of form \"x y\"\n", 1182 output->name); 1183 output->initial_x = output->initial_y = 0; 1184 } 1185 any_set = TRUE; 1186 continue; 1187 } 1188 /* 1189 * Next comes relative positions 1190 */ 1191 relation = 0; 1192 relative_name = NULL; 1193 for (r = 0; r < 4; r++) { 1194 relation = relations[r]; 1195 relative_name = xf86GetOptValString(output->options, relation); 1196 if (relative_name) 1197 break; 1198 } 1199 if (relative_name) { 1200 int or; 1201 1202 relative = NULL; 1203 for (or = 0; or < config->num_output; or++) { 1204 xf86OutputPtr out_rel = config->output[or]; 1205 XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; 1206 1207 if (rel_mon) { 1208 if (xf86nameCompare(rel_mon->mon_identifier, 1209 relative_name) == 0) { 1210 relative = config->output[or]; 1211 break; 1212 } 1213 } 1214 if (strcmp(out_rel->name, relative_name) == 0) { 1215 relative = config->output[or]; 1216 break; 1217 } 1218 } 1219 if (!relative) { 1220 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1221 "Cannot position output %s relative to unknown output %s\n", 1222 output->name, relative_name); 1223 output->initial_x = 0; 1224 output->initial_y = 0; 1225 any_set = TRUE; 1226 continue; 1227 } 1228 if (!modes[or]) { 1229 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1230 "Cannot position output %s relative to output %s without modes\n", 1231 output->name, relative_name); 1232 output->initial_x = 0; 1233 output->initial_y = 0; 1234 any_set = TRUE; 1235 continue; 1236 } 1237 if (relative->initial_x == POSITION_UNSET) { 1238 keep_going = TRUE; 1239 continue; 1240 } 1241 output->initial_x = relative->initial_x; 1242 output->initial_y = relative->initial_y; 1243 switch (relation) { 1244 case OPTION_BELOW: 1245 output->initial_y += 1246 xf86ModeHeight(modes[or], relative->initial_rotation); 1247 break; 1248 case OPTION_RIGHT_OF: 1249 output->initial_x += 1250 xf86ModeWidth(modes[or], relative->initial_rotation); 1251 break; 1252 case OPTION_ABOVE: 1253 if (modes[o]) 1254 output->initial_y -= 1255 xf86ModeHeight(modes[o], output->initial_rotation); 1256 break; 1257 case OPTION_LEFT_OF: 1258 if (modes[o]) 1259 output->initial_x -= 1260 xf86ModeWidth(modes[o], output->initial_rotation); 1261 break; 1262 default: 1263 break; 1264 } 1265 any_set = TRUE; 1266 continue; 1267 } 1268 1269 /* Nothing set, just stick them at 0,0 */ 1270 output->initial_x = 0; 1271 output->initial_y = 0; 1272 any_set = TRUE; 1273 } 1274 if (!keep_going) 1275 break; 1276 if (!any_set) { 1277 for (o = 0; o < config->num_output; o++) { 1278 xf86OutputPtr output = config->output[o]; 1279 1280 if (output->initial_x == POSITION_UNSET) { 1281 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1282 "Output position loop. Moving %s to 0,0\n", 1283 output->name); 1284 output->initial_x = output->initial_y = 0; 1285 break; 1286 } 1287 } 1288 } 1289 } 1290 1291 /* 1292 * normalize positions 1293 */ 1294 min_x = 1000000; 1295 min_y = 1000000; 1296 for (o = 0; o < config->num_output; o++) { 1297 xf86OutputPtr output = config->output[o]; 1298 1299 if (output->initial_x < min_x) 1300 min_x = output->initial_x; 1301 if (output->initial_y < min_y) 1302 min_y = output->initial_y; 1303 } 1304 1305 for (o = 0; o < config->num_output; o++) { 1306 xf86OutputPtr output = config->output[o]; 1307 1308 output->initial_x -= min_x; 1309 output->initial_y -= min_y; 1310 } 1311 return TRUE; 1312} 1313 1314static void 1315xf86InitialPanning(ScrnInfoPtr scrn) 1316{ 1317 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1318 int o; 1319 1320 for (o = 0; o < config->num_output; o++) { 1321 xf86OutputPtr output = config->output[o]; 1322 const char *panning = xf86GetOptValString(output->options, OPTION_PANNING); 1323 int width, height, left, top; 1324 int track_width, track_height, track_left, track_top; 1325 int brdr[4]; 1326 1327 memset(&output->initialTotalArea, 0, sizeof(BoxRec)); 1328 memset(&output->initialTrackingArea, 0, sizeof(BoxRec)); 1329 memset(output->initialBorder, 0, 4 * sizeof(INT16)); 1330 1331 if (!panning) 1332 continue; 1333 1334 switch (sscanf(panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 1335 &width, &height, &left, &top, 1336 &track_width, &track_height, &track_left, &track_top, 1337 &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { 1338 case 12: 1339 output->initialBorder[0] = brdr[0]; 1340 output->initialBorder[1] = brdr[1]; 1341 output->initialBorder[2] = brdr[2]; 1342 output->initialBorder[3] = brdr[3]; 1343 /* fall through */ 1344 case 8: 1345 output->initialTrackingArea.x1 = track_left; 1346 output->initialTrackingArea.y1 = track_top; 1347 output->initialTrackingArea.x2 = track_left + track_width; 1348 output->initialTrackingArea.y2 = track_top + track_height; 1349 /* fall through */ 1350 case 4: 1351 output->initialTotalArea.x1 = left; 1352 output->initialTotalArea.y1 = top; 1353 /* fall through */ 1354 case 2: 1355 output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; 1356 output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; 1357 break; 1358 default: 1359 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1360 "Broken panning specification '%s' for output %s in config file\n", 1361 panning, output->name); 1362 } 1363 } 1364} 1365 1366/** Return - 0 + if a should be earlier, same or later than b in list 1367 */ 1368static int 1369xf86ModeCompare(DisplayModePtr a, DisplayModePtr b) 1370{ 1371 int diff; 1372 1373 diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); 1374 if (diff) 1375 return diff; 1376 diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; 1377 if (diff) 1378 return diff; 1379 diff = b->Clock - a->Clock; 1380 return diff; 1381} 1382 1383/** 1384 * Insertion sort input in-place and return the resulting head 1385 */ 1386static DisplayModePtr 1387xf86SortModes(DisplayModePtr input) 1388{ 1389 DisplayModePtr output = NULL, i, o, n, *op, prev; 1390 1391 /* sort by preferred status and pixel area */ 1392 while (input) { 1393 i = input; 1394 input = input->next; 1395 for (op = &output; (o = *op); op = &o->next) 1396 if (xf86ModeCompare(o, i) > 0) 1397 break; 1398 i->next = *op; 1399 *op = i; 1400 } 1401 /* prune identical modes */ 1402 for (o = output; o && (n = o->next); o = n) { 1403 if (!strcmp(o->name, n->name) && xf86ModesEqual(o, n)) { 1404 o->next = n->next; 1405 free((void *) n->name); 1406 free(n); 1407 n = o; 1408 } 1409 } 1410 /* hook up backward links */ 1411 prev = NULL; 1412 for (o = output; o; o = o->next) { 1413 o->prev = prev; 1414 prev = o; 1415 } 1416 return output; 1417} 1418 1419static const char * 1420preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) 1421{ 1422 const char *preferred_mode = NULL; 1423 1424 /* Check for a configured preference for a particular mode */ 1425 preferred_mode = xf86GetOptValString(output->options, 1426 OPTION_PREFERRED_MODE); 1427 if (preferred_mode) 1428 return preferred_mode; 1429 1430 if (pScrn->display->modes && *pScrn->display->modes) 1431 preferred_mode = *pScrn->display->modes; 1432 1433 return preferred_mode; 1434} 1435 1436/** identify a token 1437 * args 1438 * *src a string with zero or more tokens, e.g. "tok0 tok1", 1439 * **token stores a pointer to the first token character, 1440 * *len stores the token length. 1441 * return 1442 * a pointer into src[] at the token terminating character, or 1443 * NULL if no token is found. 1444 */ 1445static const char * 1446gettoken(const char *src, const char **token, int *len) 1447{ 1448 const char *delim = " \t"; 1449 int skip; 1450 1451 if (!src) 1452 return NULL; 1453 1454 skip = strspn(src, delim); 1455 *token = &src[skip]; 1456 1457 *len = strcspn(*token, delim); 1458 /* Support for backslash escaped delimiters could be implemented 1459 * here. 1460 */ 1461 1462 /* (*token)[0] != '\0' <==> *len > 0 */ 1463 if (*len > 0) 1464 return &(*token)[*len]; 1465 else 1466 return NULL; 1467} 1468 1469/** Check for a user configured zoom mode list, Option "ZoomModes": 1470 * 1471 * Section "Monitor" 1472 * Identifier "a21inch" 1473 * Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480" 1474 * EndSection 1475 * 1476 * Each user mode name is searched for independently so the list 1477 * specification order is free. An output mode is matched at most 1478 * once, a mode with an already set M_T_USERDEF type bit is skipped. 1479 * Thus a repeat mode name specification matches the next output mode 1480 * with the same name. 1481 * 1482 * Ctrl+Alt+Keypad-{Plus,Minus} zooms {in,out} by selecting the 1483 * {next,previous} M_T_USERDEF mode in the screen modes list, itself 1484 * sorted toward lower dot area or lower dot clock frequency, see 1485 * modes/xf86Crtc.c: xf86SortModes() xf86SetScrnInfoModes(), and 1486 * common/xf86Cursor.c: xf86ZoomViewport(). 1487 */ 1488static int 1489processZoomModes(xf86OutputPtr output) 1490{ 1491 const char *zoom_modes; 1492 int count = 0; 1493 1494 zoom_modes = xf86GetOptValString(output->options, OPTION_ZOOM_MODES); 1495 1496 if (zoom_modes) { 1497 const char *token, *next; 1498 int len; 1499 1500 next = gettoken(zoom_modes, &token, &len); 1501 while (next) { 1502 DisplayModePtr mode; 1503 1504 for (mode = output->probed_modes; mode; mode = mode->next) 1505 if (!strncmp(token, mode->name, len) /* prefix match */ 1506 && mode->name[len] == '\0' /* equal length */ 1507 && !(mode->type & M_T_USERDEF)) { /* no rematch */ 1508 mode->type |= M_T_USERDEF; 1509 break; 1510 } 1511 1512 count++; 1513 next = gettoken(next, &token, &len); 1514 } 1515 } 1516 1517 return count; 1518} 1519 1520static void 1521GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) 1522{ 1523 if (!mon || !mode) 1524 return; 1525 1526 mon->nHsync = 1; 1527 mon->hsync[0].lo = 1024.0; 1528 mon->hsync[0].hi = 0.0; 1529 1530 mon->nVrefresh = 1; 1531 mon->vrefresh[0].lo = 1024.0; 1532 mon->vrefresh[0].hi = 0.0; 1533 1534 while (mode) { 1535 if (!mode->HSync) 1536 mode->HSync = ((float) mode->Clock) / ((float) mode->HTotal); 1537 1538 if (!mode->VRefresh) 1539 mode->VRefresh = (1000.0 * ((float) mode->Clock)) / 1540 ((float) (mode->HTotal * mode->VTotal)); 1541 1542 if (mode->HSync < mon->hsync[0].lo) 1543 mon->hsync[0].lo = mode->HSync; 1544 1545 if (mode->HSync > mon->hsync[0].hi) 1546 mon->hsync[0].hi = mode->HSync; 1547 1548 if (mode->VRefresh < mon->vrefresh[0].lo) 1549 mon->vrefresh[0].lo = mode->VRefresh; 1550 1551 if (mode->VRefresh > mon->vrefresh[0].hi) 1552 mon->vrefresh[0].hi = mode->VRefresh; 1553 1554 mode = mode->next; 1555 } 1556 1557 /* stretch out the bottom to fit 640x480@60 */ 1558 if (mon->hsync[0].lo > 31.0) 1559 mon->hsync[0].lo = 31.0; 1560 if (mon->vrefresh[0].lo > 58.0) 1561 mon->vrefresh[0].lo = 58.0; 1562} 1563 1564enum det_monrec_source { 1565 sync_config, sync_edid, sync_default 1566}; 1567 1568struct det_monrec_parameter { 1569 MonRec *mon_rec; 1570 int *max_clock; 1571 Bool set_hsync; 1572 Bool set_vrefresh; 1573 enum det_monrec_source *sync_source; 1574}; 1575 1576static void 1577handle_detailed_monrec(struct detailed_monitor_section *det_mon, void *data) 1578{ 1579 struct det_monrec_parameter *p; 1580 1581 p = (struct det_monrec_parameter *) data; 1582 1583 if (det_mon->type == DS_RANGES) { 1584 struct monitor_ranges *ranges = &det_mon->section.ranges; 1585 1586 if (p->set_hsync && ranges->max_h) { 1587 p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; 1588 p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; 1589 p->mon_rec->nHsync++; 1590 if (*p->sync_source == sync_default) 1591 *p->sync_source = sync_edid; 1592 } 1593 if (p->set_vrefresh && ranges->max_v) { 1594 p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; 1595 p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; 1596 p->mon_rec->nVrefresh++; 1597 if (*p->sync_source == sync_default) 1598 *p->sync_source = sync_edid; 1599 } 1600 if (ranges->max_clock * 1000 > *p->max_clock) 1601 *p->max_clock = ranges->max_clock * 1000; 1602 } 1603} 1604 1605void 1606xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY) 1607{ 1608 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1609 int o; 1610 1611 /* When canGrow was TRUE in the initial configuration we have to 1612 * compare against the maximum values so that we don't drop modes. 1613 * When canGrow was FALSE, the maximum values would have been clamped 1614 * anyway. 1615 */ 1616 if (maxX == 0 || maxY == 0) { 1617 maxX = config->maxWidth; 1618 maxY = config->maxHeight; 1619 } 1620 1621 /* Probe the list of modes for each output. */ 1622 for (o = 0; o < config->num_output; o++) { 1623 xf86OutputPtr output = config->output[o]; 1624 DisplayModePtr mode; 1625 DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; 1626 const char *preferred_mode; 1627 xf86MonPtr edid_monitor; 1628 XF86ConfMonitorPtr conf_monitor; 1629 MonRec mon_rec; 1630 int min_clock = 0; 1631 int max_clock = 0; 1632 double clock; 1633 Bool add_default_modes; 1634 Bool debug_modes = config->debug_modes || xf86Initialising; 1635 enum det_monrec_source sync_source = sync_default; 1636 1637 while (output->probed_modes != NULL) 1638 xf86DeleteMode(&output->probed_modes, output->probed_modes); 1639 1640 /* 1641 * Check connection status 1642 */ 1643 output->status = (*output->funcs->detect) (output); 1644 1645 if (output->status == XF86OutputStatusDisconnected && 1646 !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) { 1647 xf86OutputSetEDID(output, NULL); 1648 continue; 1649 } 1650 1651 memset(&mon_rec, '\0', sizeof(mon_rec)); 1652 1653 conf_monitor = output->conf_monitor; 1654 1655 if (conf_monitor) { 1656 int i; 1657 1658 for (i = 0; i < conf_monitor->mon_n_hsync; i++) { 1659 mon_rec.hsync[mon_rec.nHsync].lo = 1660 conf_monitor->mon_hsync[i].lo; 1661 mon_rec.hsync[mon_rec.nHsync].hi = 1662 conf_monitor->mon_hsync[i].hi; 1663 mon_rec.nHsync++; 1664 sync_source = sync_config; 1665 } 1666 for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) { 1667 mon_rec.vrefresh[mon_rec.nVrefresh].lo = 1668 conf_monitor->mon_vrefresh[i].lo; 1669 mon_rec.vrefresh[mon_rec.nVrefresh].hi = 1670 conf_monitor->mon_vrefresh[i].hi; 1671 mon_rec.nVrefresh++; 1672 sync_source = sync_config; 1673 } 1674 config_modes = xf86GetMonitorModes(scrn, conf_monitor); 1675 } 1676 1677 output_modes = (*output->funcs->get_modes) (output); 1678 1679 /* 1680 * If the user has a preference, respect it. 1681 * Otherwise, don't second-guess the driver. 1682 */ 1683 if (!xf86GetOptValBool(output->options, OPTION_DEFAULT_MODES, 1684 &add_default_modes)) 1685 add_default_modes = (output_modes == NULL); 1686 1687 edid_monitor = output->MonInfo; 1688 1689 if (edid_monitor) { 1690 struct det_monrec_parameter p; 1691 struct disp_features *features = &edid_monitor->features; 1692 struct cea_data_block *hdmi_db; 1693 1694 /* if display is not continuous-frequency, don't add default modes */ 1695 if (!GTF_SUPPORTED(features->msc)) 1696 add_default_modes = FALSE; 1697 1698 p.mon_rec = &mon_rec; 1699 p.max_clock = &max_clock; 1700 p.set_hsync = mon_rec.nHsync == 0; 1701 p.set_vrefresh = mon_rec.nVrefresh == 0; 1702 p.sync_source = &sync_source; 1703 1704 xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p); 1705 1706 /* Look at the CEA HDMI vendor block for the max TMDS freq */ 1707 hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor); 1708 if (hdmi_db && hdmi_db->len >= 7) { 1709 int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000; 1710 xf86DrvMsg(scrn->scrnIndex, X_PROBED, 1711 "HDMI max TMDS frequency %dKHz\n", tmds_freq); 1712 if (tmds_freq > max_clock) 1713 max_clock = tmds_freq; 1714 } 1715 } 1716 1717 if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK, 1718 OPTUNITS_KHZ, &clock)) 1719 min_clock = (int) clock; 1720 if (xf86GetOptValFreq(output->options, OPTION_MAX_CLOCK, 1721 OPTUNITS_KHZ, &clock)) 1722 max_clock = (int) clock; 1723 1724 /* If we still don't have a sync range, guess wildly */ 1725 if (!mon_rec.nHsync || !mon_rec.nVrefresh) 1726 GuessRangeFromModes(&mon_rec, output_modes); 1727 1728 /* 1729 * These limits will end up setting a 1024x768@60Hz mode by default, 1730 * which seems like a fairly good mode to use when nothing else is 1731 * specified 1732 */ 1733 if (mon_rec.nHsync == 0) { 1734 mon_rec.hsync[0].lo = 31.0; 1735 mon_rec.hsync[0].hi = 55.0; 1736 mon_rec.nHsync = 1; 1737 } 1738 if (mon_rec.nVrefresh == 0) { 1739 mon_rec.vrefresh[0].lo = 58.0; 1740 mon_rec.vrefresh[0].hi = 62.0; 1741 mon_rec.nVrefresh = 1; 1742 } 1743 1744 if (add_default_modes) 1745 default_modes = xf86GetDefaultModes(); 1746 1747 /* 1748 * If this is not an RB monitor, remove RB modes from the default 1749 * pool. RB modes from the config or the monitor itself are fine. 1750 */ 1751 if (!mon_rec.reducedblanking) 1752 xf86ValidateModesReducedBlanking(scrn, default_modes); 1753 1754 if (sync_source == sync_config) { 1755 /* 1756 * Check output and config modes against sync range from config file 1757 */ 1758 xf86ValidateModesSync(scrn, output_modes, &mon_rec); 1759 xf86ValidateModesSync(scrn, config_modes, &mon_rec); 1760 } 1761 /* 1762 * Check default modes against sync range 1763 */ 1764 xf86ValidateModesSync(scrn, default_modes, &mon_rec); 1765 /* 1766 * Check default modes against monitor max clock 1767 */ 1768 if (max_clock) { 1769 xf86ValidateModesClocks(scrn, default_modes, 1770 &min_clock, &max_clock, 1); 1771 xf86ValidateModesClocks(scrn, output_modes, 1772 &min_clock, &max_clock, 1); 1773 } 1774 1775 output->probed_modes = NULL; 1776 output->probed_modes = xf86ModesAdd(output->probed_modes, config_modes); 1777 output->probed_modes = xf86ModesAdd(output->probed_modes, output_modes); 1778 output->probed_modes = 1779 xf86ModesAdd(output->probed_modes, default_modes); 1780 1781 /* 1782 * Check all modes against max size, interlace, and doublescan 1783 */ 1784 if (maxX && maxY) 1785 xf86ValidateModesSize(scrn, output->probed_modes, maxX, maxY, 0); 1786 1787 { 1788 int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | 1789 (output->doubleScanAllowed ? V_DBLSCAN : 0); 1790 xf86ValidateModesFlags(scrn, output->probed_modes, flags); 1791 } 1792 1793 /* 1794 * Check all modes against output 1795 */ 1796 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1797 if (mode->status == MODE_OK) 1798 mode->status = (*output->funcs->mode_valid) (output, mode); 1799 1800 xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); 1801 1802 output->probed_modes = xf86SortModes(output->probed_modes); 1803 1804 /* Check for a configured preference for a particular mode */ 1805 preferred_mode = preferredMode(scrn, output); 1806 1807 if (preferred_mode) { 1808 for (mode = output->probed_modes; mode; mode = mode->next) { 1809 if (!strcmp(preferred_mode, mode->name)) { 1810 if (mode != output->probed_modes) { 1811 if (mode->prev) 1812 mode->prev->next = mode->next; 1813 if (mode->next) 1814 mode->next->prev = mode->prev; 1815 mode->next = output->probed_modes; 1816 output->probed_modes->prev = mode; 1817 mode->prev = NULL; 1818 output->probed_modes = mode; 1819 } 1820 mode->type |= (M_T_PREFERRED | M_T_USERPREF); 1821 break; 1822 } 1823 } 1824 } 1825 1826 /* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode: M_T_USERDEF mode type */ 1827 processZoomModes(output); 1828 1829 output->initial_rotation = xf86OutputInitialRotation(output); 1830 1831 if (debug_modes) { 1832 if (output->probed_modes != NULL) { 1833 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1834 "Printing probed modes for output %s\n", 1835 output->name); 1836 } 1837 else { 1838 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1839 "No remaining probed modes for output %s\n", 1840 output->name); 1841 } 1842 } 1843 for (mode = output->probed_modes; mode != NULL; mode = mode->next) { 1844 /* The code to choose the best mode per pipe later on will require 1845 * VRefresh to be set. 1846 */ 1847 mode->VRefresh = xf86ModeVRefresh(mode); 1848 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 1849 1850 if (debug_modes) 1851 xf86PrintModeline(scrn->scrnIndex, mode); 1852 } 1853 } 1854} 1855 1856/** 1857 * Copy one of the output mode lists to the ScrnInfo record 1858 */ 1859 1860static DisplayModePtr 1861biggestMode(DisplayModePtr a, DisplayModePtr b) 1862{ 1863 int A, B; 1864 1865 if (!a) 1866 return b; 1867 if (!b) 1868 return a; 1869 1870 A = a->HDisplay * a->VDisplay; 1871 B = b->HDisplay * b->VDisplay; 1872 1873 if (A > B) 1874 return a; 1875 1876 return b; 1877} 1878 1879static xf86OutputPtr 1880SetCompatOutput(xf86CrtcConfigPtr config) 1881{ 1882 xf86OutputPtr output = NULL, test = NULL; 1883 DisplayModePtr maxmode = NULL, testmode, mode; 1884 int o, compat = -1, count, mincount = 0; 1885 1886 if (config->num_output == 0) 1887 return NULL; 1888 1889 /* Look for one that's definitely connected */ 1890 for (o = 0; o < config->num_output; o++) { 1891 test = config->output[o]; 1892 if (!test->crtc) 1893 continue; 1894 if (test->status != XF86OutputStatusConnected) 1895 continue; 1896 if (!test->probed_modes) 1897 continue; 1898 1899 testmode = mode = test->probed_modes; 1900 for (count = 0; mode; mode = mode->next, count++) 1901 testmode = biggestMode(testmode, mode); 1902 1903 if (!output) { 1904 output = test; 1905 compat = o; 1906 maxmode = testmode; 1907 mincount = count; 1908 } 1909 else if (maxmode == biggestMode(maxmode, testmode)) { 1910 output = test; 1911 compat = o; 1912 maxmode = testmode; 1913 mincount = count; 1914 } 1915 else if ((maxmode->HDisplay == testmode->HDisplay) && 1916 (maxmode->VDisplay == testmode->VDisplay) && 1917 count <= mincount) { 1918 output = test; 1919 compat = o; 1920 maxmode = testmode; 1921 mincount = count; 1922 } 1923 } 1924 1925 /* If we didn't find one, take anything we can get */ 1926 if (!output) { 1927 for (o = 0; o < config->num_output; o++) { 1928 test = config->output[o]; 1929 if (!test->crtc) 1930 continue; 1931 if (!test->probed_modes) 1932 continue; 1933 1934 if (!output) { 1935 output = test; 1936 compat = o; 1937 } 1938 else if (test->probed_modes->HDisplay < 1939 output->probed_modes->HDisplay) { 1940 output = test; 1941 compat = o; 1942 } 1943 } 1944 } 1945 1946 if (compat >= 0) { 1947 config->compat_output = compat; 1948 } 1949 else if (config->compat_output >= 0 && config->compat_output < config->num_output) { 1950 /* Don't change the compat output when no valid outputs found */ 1951 output = config->output[config->compat_output]; 1952 } 1953 1954 /* All outputs are disconnected, select one to fake */ 1955 if (!output && config->num_output) { 1956 config->compat_output = 0; 1957 output = config->output[config->compat_output]; 1958 } 1959 1960 return output; 1961} 1962 1963void 1964xf86SetScrnInfoModes(ScrnInfoPtr scrn) 1965{ 1966 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1967 xf86OutputPtr output; 1968 xf86CrtcPtr crtc; 1969 DisplayModePtr last, mode = NULL; 1970 1971 output = SetCompatOutput(config); 1972 1973 if (!output) 1974 return; /* punt */ 1975 1976 crtc = output->crtc; 1977 1978 /* Clear any existing modes from scrn->modes */ 1979 while (scrn->modes != NULL) 1980 xf86DeleteMode(&scrn->modes, scrn->modes); 1981 1982 /* Set scrn->modes to the mode list for the 'compat' output */ 1983 scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); 1984 1985 if (crtc) { 1986 for (mode = scrn->modes; mode; mode = mode->next) 1987 if (xf86ModesEqual(mode, &crtc->desiredMode)) 1988 break; 1989 } 1990 1991 if (!scrn->modes) { 1992 scrn->modes = xf86ModesAdd(scrn->modes, 1993 xf86CVTMode(scrn->display->virtualX, 1994 scrn->display->virtualY, 1995 60, 0, 0)); 1996 } 1997 1998 /* For some reason, scrn->modes is circular, unlike the other mode 1999 * lists. How great is that? 2000 */ 2001 for (last = scrn->modes; last && last->next; last = last->next); 2002 last->next = scrn->modes; 2003 scrn->modes->prev = last; 2004 if (mode) { 2005 while (scrn->modes != mode) 2006 scrn->modes = scrn->modes->next; 2007 } 2008 2009 scrn->currentMode = scrn->modes; 2010#ifdef XFreeXDGA 2011 if (scrn->pScreen) 2012 _xf86_di_dga_reinit_internal(scrn->pScreen); 2013#endif 2014} 2015 2016static Bool 2017xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2018 Bool *enabled) 2019{ 2020 Bool any_enabled = FALSE; 2021 int o; 2022 2023 /* 2024 * Don't bother enabling outputs on GPU screens: a client needs to attach 2025 * it to a source provider before setting a mode that scans out a shared 2026 * pixmap. 2027 */ 2028 if (scrn->is_gpu) 2029 return FALSE; 2030 2031 for (o = 0; o < config->num_output; o++) 2032 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); 2033 2034 if (!any_enabled) { 2035 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2036 "No outputs definitely connected, trying again...\n"); 2037 2038 for (o = 0; o < config->num_output; o++) 2039 any_enabled |= enabled[o] = 2040 xf86OutputEnabled(config->output[o], FALSE); 2041 } 2042 2043 return any_enabled; 2044} 2045 2046static Bool 2047nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) 2048{ 2049 int o = *index; 2050 2051 for (o++; o < config->num_output; o++) { 2052 if (enabled[o]) { 2053 *index = o; 2054 return TRUE; 2055 } 2056 } 2057 2058 return FALSE; 2059} 2060 2061static Bool 2062aspectMatch(float a, float b) 2063{ 2064 return fabs(1 - (a / b)) < 0.05; 2065} 2066 2067static DisplayModePtr 2068nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) 2069{ 2070 DisplayModePtr m = NULL; 2071 2072 if (!o) 2073 return NULL; 2074 2075 if (!last) 2076 m = o->probed_modes; 2077 else 2078 m = last->next; 2079 2080 for (; m; m = m->next) 2081 if (aspectMatch(aspect, (float) m->HDisplay / (float) m->VDisplay)) 2082 return m; 2083 2084 return NULL; 2085} 2086 2087static DisplayModePtr 2088bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) 2089{ 2090 int o = -1, p; 2091 DisplayModePtr mode = NULL, test = NULL, match = NULL; 2092 2093 if (!nextEnabledOutput(config, enabled, &o)) 2094 return NULL; 2095 while ((mode = nextAspectMode(config->output[o], mode, aspect))) { 2096 test = mode; 2097 for (p = o; nextEnabledOutput(config, enabled, &p);) { 2098 test = xf86OutputFindClosestMode(config->output[p], mode); 2099 if (!test) 2100 break; 2101 if (test->HDisplay != mode->HDisplay || 2102 test->VDisplay != mode->VDisplay) { 2103 test = NULL; 2104 break; 2105 } 2106 } 2107 2108 /* if we didn't match it on all outputs, try the next one */ 2109 if (!test) 2110 continue; 2111 2112 /* if it's bigger than the last one, save it */ 2113 if (!match || (test->HDisplay > match->HDisplay)) 2114 match = test; 2115 } 2116 2117 /* return the biggest one found */ 2118 return match; 2119} 2120 2121static int 2122numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled) 2123{ 2124 int i = 0, p; 2125 2126 for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; 2127 2128 return i; 2129} 2130 2131static Bool 2132xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2133 DisplayModePtr *modes, Bool *enabled, 2134 int width, int height) 2135{ 2136 int o; 2137 int w = 0; 2138 Bool has_tile = FALSE; 2139 uint32_t configured_outputs; 2140 2141 if (scrn->preferClone) 2142 return FALSE; 2143 2144 if (numEnabledOutputs(config, enabled) < 2) 2145 return FALSE; 2146 2147 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2148 DisplayModePtr mode = 2149 xf86OutputHasPreferredMode(config->output[o], width, height); 2150 2151 if (!mode) 2152 return FALSE; 2153 2154 w += mode->HDisplay; 2155 } 2156 2157 if (w > width) 2158 return FALSE; 2159 2160 w = 0; 2161 configured_outputs = 0; 2162 2163 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2164 DisplayModePtr mode = 2165 xf86OutputHasPreferredMode(config->output[o], width, height); 2166 2167 if (configured_outputs & (1 << o)) 2168 continue; 2169 2170 if (config->output[o]->tile_info.group_id) { 2171 has_tile = TRUE; 2172 continue; 2173 } 2174 2175 config->output[o]->initial_x = w; 2176 w += mode->HDisplay; 2177 2178 configured_outputs |= (1 << o); 2179 modes[o] = mode; 2180 } 2181 2182 if (has_tile) { 2183 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2184 int ht, vt, ot; 2185 int add_x, cur_x = w; 2186 struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile; 2187 if (configured_outputs & (1 << o)) 2188 continue; 2189 if (!tile_info->group_id) 2190 continue; 2191 2192 if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0) 2193 continue; 2194 2195 for (ht = 0; ht < tile_info->num_h_tile; ht++) { 2196 int cur_y = 0; 2197 add_x = 0; 2198 for (vt = 0; vt < tile_info->num_v_tile; vt++) { 2199 2200 for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) { 2201 2202 DisplayModePtr mode = 2203 xf86OutputHasPreferredMode(config->output[ot], width, height); 2204 if (!config->output[ot]->tile_info.group_id) 2205 continue; 2206 2207 this_tile = &config->output[ot]->tile_info; 2208 if (this_tile->group_id != tile_info->group_id) 2209 continue; 2210 2211 if (this_tile->tile_h_loc != ht || 2212 this_tile->tile_v_loc != vt) 2213 continue; 2214 2215 config->output[ot]->initial_x = cur_x; 2216 config->output[ot]->initial_y = cur_y; 2217 2218 if (vt == 0) 2219 add_x = this_tile->tile_h_size; 2220 cur_y += this_tile->tile_v_size; 2221 configured_outputs |= (1 << ot); 2222 modes[ot] = mode; 2223 } 2224 } 2225 cur_x += add_x; 2226 } 2227 w = cur_x; 2228 } 2229 } 2230 return TRUE; 2231} 2232 2233static Bool 2234xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2235 DisplayModePtr * modes, Bool *enabled, 2236 int width, int height) 2237{ 2238 int o, p; 2239 int max_pref_width = 0, max_pref_height = 0; 2240 DisplayModePtr *preferred, *preferred_match; 2241 Bool ret = FALSE; 2242 2243 preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2244 preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2245 2246 /* Check if the preferred mode is available on all outputs */ 2247 for (p = -1; nextEnabledOutput(config, enabled, &p);) { 2248 Rotation r = config->output[p]->initial_rotation; 2249 DisplayModePtr mode; 2250 2251 if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], 2252 width, height))) { 2253 int pref_width = xf86ModeWidth(preferred[p], r); 2254 int pref_height = xf86ModeHeight(preferred[p], r); 2255 Bool all_match = TRUE; 2256 2257 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2258 Bool match = FALSE; 2259 xf86OutputPtr output = config->output[o]; 2260 2261 if (o == p) 2262 continue; 2263 2264 /* 2265 * First see if the preferred mode matches on the next 2266 * output as well. This catches the common case of identical 2267 * monitors and makes sure they all have the same timings 2268 * and refresh. If that fails, we fall back to trying to 2269 * match just width & height. 2270 */ 2271 mode = xf86OutputHasPreferredMode(output, pref_width, 2272 pref_height); 2273 if (mode && xf86ModesEqual(mode, preferred[p])) { 2274 preferred[o] = mode; 2275 match = TRUE; 2276 } 2277 else { 2278 for (mode = output->probed_modes; mode; mode = mode->next) { 2279 Rotation ir = output->initial_rotation; 2280 2281 if (xf86ModeWidth(mode, ir) == pref_width && 2282 xf86ModeHeight(mode, ir) == pref_height) { 2283 preferred[o] = mode; 2284 match = TRUE; 2285 } 2286 } 2287 } 2288 2289 all_match &= match; 2290 } 2291 2292 if (all_match && 2293 (pref_width * pref_height > max_pref_width * max_pref_height)) { 2294 for (o = -1; nextEnabledOutput(config, enabled, &o);) 2295 preferred_match[o] = preferred[o]; 2296 max_pref_width = pref_width; 2297 max_pref_height = pref_height; 2298 ret = TRUE; 2299 } 2300 } 2301 } 2302 2303 /* 2304 * If there's no preferred mode, but only one monitor, pick the 2305 * biggest mode for its aspect ratio or 4:3, assuming one exists. 2306 */ 2307 if (!ret) 2308 do { 2309 float aspect = 0.0; 2310 DisplayModePtr a = NULL, b = NULL; 2311 2312 if (numEnabledOutputs(config, enabled) != 1) 2313 break; 2314 2315 p = -1; 2316 nextEnabledOutput(config, enabled, &p); 2317 if (config->output[p]->mm_height) 2318 aspect = (float) config->output[p]->mm_width / 2319 (float) config->output[p]->mm_height; 2320 2321 a = bestModeForAspect(config, enabled, 4.0/3.0); 2322 if (aspect) 2323 b = bestModeForAspect(config, enabled, aspect); 2324 2325 preferred_match[p] = biggestMode(a, b); 2326 2327 if (preferred_match[p]) 2328 ret = TRUE; 2329 2330 } while (0); 2331 2332 if (ret) { 2333 /* oh good, there is a match. stash the selected modes and return. */ 2334 memcpy(modes, preferred_match, 2335 config->num_output * sizeof(DisplayModePtr)); 2336 } 2337 2338 free(preferred); 2339 free(preferred_match); 2340 return ret; 2341} 2342 2343static Bool 2344xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2345 DisplayModePtr * modes, Bool *enabled, int width, int height) 2346{ 2347 int o; 2348 float aspect = 0.0, *aspects; 2349 xf86OutputPtr output; 2350 Bool ret = FALSE; 2351 DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; 2352 2353 aspects = xnfcalloc(config->num_output, sizeof(float)); 2354 2355 /* collect the aspect ratios */ 2356 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2357 output = config->output[o]; 2358 if (output->mm_height) 2359 aspects[o] = (float) output->mm_width / (float) output->mm_height; 2360 else 2361 aspects[o] = 4.0 / 3.0; 2362 } 2363 2364 /* check that they're all the same */ 2365 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2366 output = config->output[o]; 2367 if (!aspect) { 2368 aspect = aspects[o]; 2369 } 2370 else if (!aspectMatch(aspect, aspects[o])) { 2371 goto no_aspect_match; 2372 } 2373 } 2374 2375 /* if they're all 4:3, just skip ahead and save effort */ 2376 if (!aspectMatch(aspect, 4.0 / 3.0)) 2377 aspect_guess = bestModeForAspect(config, enabled, aspect); 2378 2379 no_aspect_match: 2380 base_guess = bestModeForAspect(config, enabled, 4.0 / 3.0); 2381 2382 guess = biggestMode(base_guess, aspect_guess); 2383 2384 if (!guess) 2385 goto out; 2386 2387 /* found a mode that works everywhere, now apply it */ 2388 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2389 modes[o] = xf86OutputFindClosestMode(config->output[o], guess); 2390 } 2391 ret = TRUE; 2392 2393 out: 2394 free(aspects); 2395 return ret; 2396} 2397 2398static Bool 2399xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2400 DisplayModePtr * modes, Bool *enabled, int width, int height) 2401{ 2402 DisplayModePtr target_mode = NULL; 2403 Rotation target_rotation = RR_Rotate_0; 2404 DisplayModePtr default_mode; 2405 int default_preferred, target_preferred = 0, o; 2406 2407 /* User preferred > preferred > other modes */ 2408 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2409 default_mode = xf86DefaultMode(config->output[o], width, height); 2410 if (!default_mode) 2411 continue; 2412 2413 default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + 2414 ((default_mode->type & M_T_USERPREF) != 0)); 2415 2416 if (default_preferred > target_preferred || !target_mode) { 2417 target_mode = default_mode; 2418 target_preferred = default_preferred; 2419 target_rotation = config->output[o]->initial_rotation; 2420 config->compat_output = o; 2421 } 2422 } 2423 2424 if (target_mode) 2425 modes[config->compat_output] = target_mode; 2426 2427 /* Fill in other output modes */ 2428 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2429 if (!modes[o]) 2430 modes[o] = xf86ClosestMode(config->output[o], target_mode, 2431 target_rotation, width, height); 2432 } 2433 2434 return target_mode != NULL; 2435} 2436 2437static Bool 2438xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2439 DisplayModePtr * modes, Bool *enabled, int width, int height) 2440{ 2441 int o; 2442 2443 if (xf86UserConfiguredOutputs(scrn, modes)) 2444 return xf86TargetFallback(scrn, config, modes, enabled, width, height); 2445 2446 for (o = -1; nextEnabledOutput(config, enabled, &o);) 2447 if (xf86OutputHasUserPreferredMode(config->output[o])) 2448 return 2449 xf86TargetFallback(scrn, config, modes, enabled, width, height); 2450 2451 return FALSE; 2452} 2453 2454static Bool 2455xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, 2456 float gamma_blue) 2457{ 2458 int i, size = 256; 2459 CARD16 *red, *green, *blue; 2460 2461 red = xallocarray(size, 3 * sizeof(CARD16)); 2462 green = red + size; 2463 blue = green + size; 2464 2465 /* Only cause warning if user wanted gamma to be set. */ 2466 if (!crtc->funcs->gamma_set && 2467 (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { 2468 free(red); 2469 return FALSE; 2470 } 2471 else if (!crtc->funcs->gamma_set) { 2472 free(red); 2473 return TRUE; 2474 } 2475 2476 /* At this early stage none of the randr-interface stuff is up. 2477 * So take the default gamma size for lack of something better. 2478 */ 2479 for (i = 0; i < size; i++) { 2480 if (gamma_red == 1.0) 2481 red[i] = i << 8; 2482 else 2483 red[i] = (CARD16) (pow((double) i / (double) (size - 1), 2484 1. / (double) gamma_red) * (double) (size - 2485 1) * 2486 256); 2487 2488 if (gamma_green == 1.0) 2489 green[i] = i << 8; 2490 else 2491 green[i] = (CARD16) (pow((double) i / (double) (size - 1), 2492 1. / (double) gamma_green) * 2493 (double) (size - 1) * 256); 2494 2495 if (gamma_blue == 1.0) 2496 blue[i] = i << 8; 2497 else 2498 blue[i] = (CARD16) (pow((double) i / (double) (size - 1), 2499 1. / (double) gamma_blue) * (double) (size - 2500 1) * 2501 256); 2502 } 2503 2504 /* Default size is 256, so anything else is failure. */ 2505 if (size != crtc->gamma_size) { 2506 free(red); 2507 return FALSE; 2508 } 2509 2510 crtc->gamma_size = size; 2511 memcpy(crtc->gamma_red, red, crtc->gamma_size * sizeof(CARD16)); 2512 memcpy(crtc->gamma_green, green, crtc->gamma_size * sizeof(CARD16)); 2513 memcpy(crtc->gamma_blue, blue, crtc->gamma_size * sizeof(CARD16)); 2514 2515 /* Do not set gamma now, delay until the crtc is activated. */ 2516 2517 free(red); 2518 2519 return TRUE; 2520} 2521 2522static Bool 2523xf86OutputSetInitialGamma(xf86OutputPtr output) 2524{ 2525 XF86ConfMonitorPtr mon = output->conf_monitor; 2526 float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; 2527 2528 if (!mon) 2529 return TRUE; 2530 2531 if (!output->crtc) 2532 return FALSE; 2533 2534 /* Get configured values, where they exist. */ 2535 if (mon->mon_gamma_red >= GAMMA_MIN && mon->mon_gamma_red <= GAMMA_MAX) 2536 gamma_red = mon->mon_gamma_red; 2537 2538 if (mon->mon_gamma_green >= GAMMA_MIN && mon->mon_gamma_green <= GAMMA_MAX) 2539 gamma_green = mon->mon_gamma_green; 2540 2541 if (mon->mon_gamma_blue >= GAMMA_MIN && mon->mon_gamma_blue <= GAMMA_MAX) 2542 gamma_blue = mon->mon_gamma_blue; 2543 2544 /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ 2545 if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { 2546 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 2547 "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", 2548 output->name, gamma_red, gamma_green, gamma_blue); 2549 return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, 2550 gamma_blue); 2551 } 2552 else 2553 return TRUE; 2554} 2555 2556/** 2557 * Construct default screen configuration 2558 * 2559 * Given auto-detected (and, eventually, configured) values, 2560 * construct a usable configuration for the system 2561 * 2562 * canGrow indicates that the driver can resize the screen to larger than its 2563 * initially configured size via the config->funcs->resize hook. If TRUE, this 2564 * function will set virtualX and virtualY to match the initial configuration 2565 * and leave config->max{Width,Height} alone. If FALSE, it will bloat 2566 * virtual[XY] to include the largest modes and set config->max{Width,Height} 2567 * accordingly. 2568 */ 2569 2570Bool 2571xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow) 2572{ 2573 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2574 int o, c; 2575 xf86CrtcPtr *crtcs; 2576 DisplayModePtr *modes; 2577 Bool *enabled; 2578 int width, height; 2579 int i = scrn->scrnIndex; 2580 Bool have_outputs = TRUE; 2581 Bool ret; 2582 Bool success = FALSE; 2583 2584 /* Set up the device options */ 2585 config->options = xnfalloc(sizeof(xf86DeviceOptions)); 2586 memcpy(config->options, xf86DeviceOptions, sizeof(xf86DeviceOptions)); 2587 xf86ProcessOptions(scrn->scrnIndex, scrn->options, config->options); 2588 config->debug_modes = xf86ReturnOptValBool(config->options, 2589 OPTION_MODEDEBUG, FALSE); 2590 2591 if (scrn->display->virtualX && !scrn->is_gpu) 2592 width = scrn->display->virtualX; 2593 else 2594 width = config->maxWidth; 2595 if (scrn->display->virtualY && !scrn->is_gpu) 2596 height = scrn->display->virtualY; 2597 else 2598 height = config->maxHeight; 2599 2600 xf86ProbeOutputModes(scrn, width, height); 2601 2602 crtcs = xnfcalloc(config->num_output, sizeof(xf86CrtcPtr)); 2603 modes = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2604 enabled = xnfcalloc(config->num_output, sizeof(Bool)); 2605 2606 ret = xf86CollectEnabledOutputs(scrn, config, enabled); 2607 if (ret == FALSE && canGrow) { 2608 if (!scrn->is_gpu) 2609 xf86DrvMsg(i, X_WARNING, 2610 "Unable to find connected outputs - setting %dx%d " 2611 "initial framebuffer\n", 2612 NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); 2613 have_outputs = FALSE; 2614 } 2615 else { 2616 if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) 2617 xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); 2618 else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height)) 2619 xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n"); 2620 else if (xf86TargetPreferred 2621 (scrn, config, modes, enabled, width, height)) 2622 xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); 2623 else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) 2624 xf86DrvMsg(i, X_INFO, 2625 "Using fuzzy aspect match for initial modes\n"); 2626 else if (xf86TargetFallback 2627 (scrn, config, modes, enabled, width, height)) 2628 xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); 2629 else 2630 xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); 2631 } 2632 2633 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2634 if (!modes[o]) 2635 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2636 "Output %s enabled but has no modes\n", 2637 config->output[o]->name); 2638 else 2639 xf86DrvMsg (scrn->scrnIndex, X_INFO, 2640 "Output %s using initial mode %s +%d+%d\n", 2641 config->output[o]->name, modes[o]->name, 2642 config->output[o]->initial_x, 2643 config->output[o]->initial_y); 2644 } 2645 2646 /* 2647 * Set the position of each output 2648 */ 2649 if (!xf86InitialOutputPositions(scrn, modes)) 2650 goto bailout; 2651 2652 /* 2653 * Set initial panning of each output 2654 */ 2655 xf86InitialPanning(scrn); 2656 2657 /* 2658 * Assign CRTCs to fit output configuration 2659 */ 2660 if (have_outputs && !xf86PickCrtcs(scrn, crtcs, modes, 0, width, height)) 2661 goto bailout; 2662 2663 /* XXX override xf86 common frame computation code */ 2664 2665 if (!scrn->is_gpu) { 2666 scrn->display->frameX0 = 0; 2667 scrn->display->frameY0 = 0; 2668 } 2669 2670 for (c = 0; c < config->num_crtc; c++) { 2671 xf86CrtcPtr crtc = config->crtc[c]; 2672 2673 crtc->enabled = FALSE; 2674 memset(&crtc->desiredMode, '\0', sizeof(crtc->desiredMode)); 2675 /* Set default gamma for all crtc's. */ 2676 /* This is done to avoid problems later on with cloned outputs. */ 2677 xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); 2678 } 2679 2680 if (xf86_crtc_supports_gamma(scrn)) 2681 xf86DrvMsg(scrn->scrnIndex, X_INFO, 2682 "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); 2683 2684 /* 2685 * Set initial configuration 2686 */ 2687 for (o = 0; o < config->num_output; o++) { 2688 xf86OutputPtr output = config->output[o]; 2689 DisplayModePtr mode = modes[o]; 2690 xf86CrtcPtr crtc = crtcs[o]; 2691 2692 if (mode && crtc) { 2693 xf86SaveModeContents(&crtc->desiredMode, mode); 2694 crtc->desiredRotation = output->initial_rotation; 2695 crtc->desiredX = output->initial_x; 2696 crtc->desiredY = output->initial_y; 2697 crtc->desiredTransformPresent = FALSE; 2698 crtc->enabled = TRUE; 2699 memcpy(&crtc->panningTotalArea, &output->initialTotalArea, 2700 sizeof(BoxRec)); 2701 memcpy(&crtc->panningTrackingArea, &output->initialTrackingArea, 2702 sizeof(BoxRec)); 2703 memcpy(crtc->panningBorder, output->initialBorder, 2704 4 * sizeof(INT16)); 2705 output->crtc = crtc; 2706 if (!xf86OutputSetInitialGamma(output)) 2707 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2708 "Initial gamma correction for output %s: failed.\n", 2709 output->name); 2710 } 2711 else { 2712 output->crtc = NULL; 2713 } 2714 } 2715 2716 if (scrn->display->virtualX == 0 || scrn->is_gpu) { 2717 /* 2718 * Expand virtual size to cover the current config and potential mode 2719 * switches, if the driver can't enlarge the screen later. 2720 */ 2721 xf86DefaultScreenLimits(scrn, &width, &height, canGrow); 2722 2723 if (have_outputs == FALSE) { 2724 if (width < NO_OUTPUT_DEFAULT_WIDTH && 2725 height < NO_OUTPUT_DEFAULT_HEIGHT) { 2726 width = NO_OUTPUT_DEFAULT_WIDTH; 2727 height = NO_OUTPUT_DEFAULT_HEIGHT; 2728 } 2729 } 2730 2731 if (!scrn->is_gpu) { 2732 scrn->display->virtualX = width; 2733 scrn->display->virtualY = height; 2734 } 2735 } 2736 2737 if (width > scrn->virtualX) 2738 scrn->virtualX = width; 2739 if (height > scrn->virtualY) 2740 scrn->virtualY = height; 2741 2742 /* 2743 * Make sure the configuration isn't too small. 2744 */ 2745 if (width < config->minWidth || height < config->minHeight) 2746 goto bailout; 2747 2748 /* 2749 * Limit the crtc config to virtual[XY] if the driver can't grow the 2750 * desktop. 2751 */ 2752 if (!canGrow) { 2753 xf86CrtcSetSizeRange(scrn, config->minWidth, config->minHeight, 2754 width, height); 2755 } 2756 2757 xf86SetScrnInfoModes(scrn); 2758 2759 success = TRUE; 2760 bailout: 2761 free(crtcs); 2762 free(modes); 2763 free(enabled); 2764 return success; 2765} 2766 2767/* 2768 * Check the CRTC we're going to map each output to vs. it's current 2769 * CRTC. If they don't match, we have to disable the output and the CRTC 2770 * since the driver will have to re-route things. 2771 */ 2772static void 2773xf86PrepareOutputs(ScrnInfoPtr scrn) 2774{ 2775 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2776 int o; 2777 2778 for (o = 0; o < config->num_output; o++) { 2779 xf86OutputPtr output = config->output[o]; 2780 2781#if RANDR_GET_CRTC_INTERFACE 2782 /* Disable outputs that are unused or will be re-routed */ 2783 if (!output->funcs->get_crtc || 2784 output->crtc != (*output->funcs->get_crtc) (output) || 2785 output->crtc == NULL) 2786#endif 2787 (*output->funcs->dpms) (output, DPMSModeOff); 2788 } 2789} 2790 2791static void 2792xf86PrepareCrtcs(ScrnInfoPtr scrn) 2793{ 2794 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2795 int c; 2796 2797 for (c = 0; c < config->num_crtc; c++) { 2798#if RANDR_GET_CRTC_INTERFACE 2799 xf86CrtcPtr crtc = config->crtc[c]; 2800 xf86OutputPtr output = NULL; 2801 uint32_t desired_outputs = 0, current_outputs = 0; 2802 int o; 2803 2804 for (o = 0; o < config->num_output; o++) { 2805 output = config->output[o]; 2806 if (output->crtc == crtc) 2807 desired_outputs |= (1 << o); 2808 /* If we can't tell where it's mapped, force it off */ 2809 if (!output->funcs->get_crtc) { 2810 desired_outputs = 0; 2811 break; 2812 } 2813 if ((*output->funcs->get_crtc) (output) == crtc) 2814 current_outputs |= (1 << o); 2815 } 2816 2817 /* 2818 * If mappings are different or the CRTC is unused, 2819 * we need to disable it 2820 */ 2821 if (desired_outputs != current_outputs || !desired_outputs) 2822 (*crtc->funcs->dpms) (crtc, DPMSModeOff); 2823#else 2824 (*crtc->funcs->dpms) (crtc, DPMSModeOff); 2825#endif 2826 } 2827} 2828 2829/* 2830 * Using the desired mode information in each crtc, set 2831 * modes (used in EnterVT functions, or at server startup) 2832 */ 2833 2834Bool 2835xf86SetDesiredModes(ScrnInfoPtr scrn) 2836{ 2837 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2838 xf86CrtcPtr crtc = config->crtc[0]; 2839 int enabled = 0, failed = 0; 2840 int c; 2841 2842 /* A driver with this hook will take care of this */ 2843 if (!crtc->funcs->set_mode_major) { 2844 xf86PrepareOutputs(scrn); 2845 xf86PrepareCrtcs(scrn); 2846 } 2847 2848 for (c = 0; c < config->num_crtc; c++) { 2849 xf86OutputPtr output = NULL; 2850 int o; 2851 RRTransformPtr transform; 2852 2853 crtc = config->crtc[c]; 2854 2855 /* Skip disabled CRTCs */ 2856 if (!crtc->enabled) 2857 continue; 2858 2859 if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) 2860 output = xf86CompatOutput(scrn); 2861 else { 2862 for (o = 0; o < config->num_output; o++) 2863 if (config->output[o]->crtc == crtc) { 2864 output = config->output[o]; 2865 break; 2866 } 2867 } 2868 /* paranoia */ 2869 if (!output) 2870 continue; 2871 2872 /* Mark that we'll need to re-set the mode for sure */ 2873 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2874 if (!crtc->desiredMode.CrtcHDisplay) { 2875 DisplayModePtr mode = 2876 xf86OutputFindClosestMode(output, scrn->currentMode); 2877 2878 if (!mode) 2879 return FALSE; 2880 xf86SaveModeContents(&crtc->desiredMode, mode); 2881 crtc->desiredRotation = RR_Rotate_0; 2882 crtc->desiredTransformPresent = FALSE; 2883 crtc->desiredX = 0; 2884 crtc->desiredY = 0; 2885 } 2886 2887 if (crtc->desiredTransformPresent) 2888 transform = &crtc->desiredTransform; 2889 else 2890 transform = NULL; 2891 if (xf86CrtcSetModeTransform 2892 (crtc, &crtc->desiredMode, crtc->desiredRotation, transform, 2893 crtc->desiredX, crtc->desiredY)) { 2894 ++enabled; 2895 } else { 2896 for (o = 0; o < config->num_output; o++) 2897 if (config->output[o]->crtc == crtc) 2898 config->output[o]->crtc = NULL; 2899 crtc->enabled = FALSE; 2900 ++failed; 2901 } 2902 } 2903 2904 xf86DisableUnusedFunctions(scrn); 2905 return enabled != 0 || failed == 0; 2906} 2907 2908/** 2909 * In the current world order, there are lists of modes per output, which may 2910 * or may not include the mode that was asked to be set by XFree86's mode 2911 * selection. Find the closest one, in the following preference order: 2912 * 2913 * - Equality 2914 * - Closer in size to the requested mode, but no larger 2915 * - Closer in refresh rate to the requested mode. 2916 */ 2917 2918DisplayModePtr 2919xf86OutputFindClosestMode(xf86OutputPtr output, DisplayModePtr desired) 2920{ 2921 DisplayModePtr best = NULL, scan = NULL; 2922 2923 for (scan = output->probed_modes; scan != NULL; scan = scan->next) { 2924 /* If there's an exact match, we're done. */ 2925 if (xf86ModesEqual(scan, desired)) { 2926 best = desired; 2927 break; 2928 } 2929 2930 /* Reject if it's larger than the desired mode. */ 2931 if (scan->HDisplay > desired->HDisplay || 2932 scan->VDisplay > desired->VDisplay) { 2933 continue; 2934 } 2935 2936 /* 2937 * If we haven't picked a best mode yet, use the first 2938 * one in the size range 2939 */ 2940 if (best == NULL) { 2941 best = scan; 2942 continue; 2943 } 2944 2945 /* Find if it's closer to the right size than the current best 2946 * option. 2947 */ 2948 if ((scan->HDisplay > best->HDisplay && 2949 scan->VDisplay >= best->VDisplay) || 2950 (scan->HDisplay >= best->HDisplay && 2951 scan->VDisplay > best->VDisplay)) { 2952 best = scan; 2953 continue; 2954 } 2955 2956 /* Find if it's still closer to the right refresh than the current 2957 * best resolution. 2958 */ 2959 if (scan->HDisplay == best->HDisplay && 2960 scan->VDisplay == best->VDisplay && 2961 (fabs(scan->VRefresh - desired->VRefresh) < 2962 fabs(best->VRefresh - desired->VRefresh))) { 2963 best = scan; 2964 } 2965 } 2966 return best; 2967} 2968 2969/** 2970 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, 2971 * take the specified mode and apply it to the crtc connected to the compat 2972 * output. Then, find similar modes for the other outputs, as with the 2973 * InitialConfiguration code above. The goal is to clone the desired 2974 * mode across all outputs that are currently active. 2975 */ 2976 2977Bool 2978xf86SetSingleMode(ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) 2979{ 2980 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2981 Bool ok = TRUE; 2982 xf86OutputPtr compat_output; 2983 DisplayModePtr compat_mode = NULL; 2984 int c; 2985 2986 /* 2987 * Let the compat output drive the final mode selection 2988 */ 2989 compat_output = xf86CompatOutput(pScrn); 2990 if (compat_output) 2991 compat_mode = xf86OutputFindClosestMode(compat_output, desired); 2992 if (compat_mode) 2993 desired = compat_mode; 2994 2995 for (c = 0; c < config->num_crtc; c++) { 2996 xf86CrtcPtr crtc = config->crtc[c]; 2997 DisplayModePtr crtc_mode = NULL; 2998 int o; 2999 3000 if (!crtc->enabled) 3001 continue; 3002 3003 for (o = 0; o < config->num_output; o++) { 3004 xf86OutputPtr output = config->output[o]; 3005 DisplayModePtr output_mode; 3006 3007 /* skip outputs not on this crtc */ 3008 if (output->crtc != crtc) 3009 continue; 3010 3011 if (crtc_mode) { 3012 output_mode = xf86OutputFindClosestMode(output, crtc_mode); 3013 if (output_mode != crtc_mode) 3014 output->crtc = NULL; 3015 } 3016 else 3017 crtc_mode = xf86OutputFindClosestMode(output, desired); 3018 } 3019 if (!crtc_mode) { 3020 crtc->enabled = FALSE; 3021 continue; 3022 } 3023 if (!xf86CrtcSetModeTransform(crtc, crtc_mode, rotation, NULL, 0, 0)) 3024 ok = FALSE; 3025 else { 3026 xf86SaveModeContents(&crtc->desiredMode, crtc_mode); 3027 crtc->desiredRotation = rotation; 3028 crtc->desiredTransformPresent = FALSE; 3029 crtc->desiredX = 0; 3030 crtc->desiredY = 0; 3031 } 3032 } 3033 xf86DisableUnusedFunctions(pScrn); 3034#ifdef RANDR_12_INTERFACE 3035 xf86RandR12TellChanged(pScrn->pScreen); 3036#endif 3037 return ok; 3038} 3039 3040/** 3041 * Set the DPMS power mode of all outputs and CRTCs. 3042 * 3043 * If the new mode is off, it will turn off outputs and then CRTCs. 3044 * Otherwise, it will affect CRTCs before outputs. 3045 */ 3046void 3047xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) 3048{ 3049 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3050 int i; 3051 3052 if (!scrn->vtSema) 3053 return; 3054 3055 if (mode == DPMSModeOff) { 3056 for (i = 0; i < config->num_output; i++) { 3057 xf86OutputPtr output = config->output[i]; 3058 3059 if (output->crtc != NULL) 3060 (*output->funcs->dpms) (output, mode); 3061 } 3062 } 3063 3064 for (i = 0; i < config->num_crtc; i++) { 3065 xf86CrtcPtr crtc = config->crtc[i]; 3066 3067 if (crtc->enabled) 3068 (*crtc->funcs->dpms) (crtc, mode); 3069 } 3070 3071 if (mode != DPMSModeOff) { 3072 for (i = 0; i < config->num_output; i++) { 3073 xf86OutputPtr output = config->output[i]; 3074 3075 if (output->crtc != NULL) 3076 (*output->funcs->dpms) (output, mode); 3077 } 3078 } 3079} 3080 3081/** 3082 * Implement the screensaver by just calling down into the driver DPMS hooks. 3083 * 3084 * Even for monitors with no DPMS support, by the definition of our DPMS hooks, 3085 * the outputs will still get disabled (blanked). 3086 */ 3087Bool 3088xf86SaveScreen(ScreenPtr pScreen, int mode) 3089{ 3090 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 3091 3092 if (xf86IsUnblank(mode)) 3093 xf86DPMSSet(pScrn, DPMSModeOn, 0); 3094 else 3095 xf86DPMSSet(pScrn, DPMSModeOff, 0); 3096 3097 return TRUE; 3098} 3099 3100/** 3101 * Disable all inactive crtcs and outputs 3102 */ 3103void 3104xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) 3105{ 3106 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3107 int o, c; 3108 3109 for (o = 0; o < xf86_config->num_output; o++) { 3110 xf86OutputPtr output = xf86_config->output[o]; 3111 3112 if (!output->crtc) 3113 (*output->funcs->dpms) (output, DPMSModeOff); 3114 } 3115 3116 for (c = 0; c < xf86_config->num_crtc; c++) { 3117 xf86CrtcPtr crtc = xf86_config->crtc[c]; 3118 3119 if (!crtc->enabled) { 3120 crtc->funcs->dpms(crtc, DPMSModeOff); 3121 memset(&crtc->mode, 0, sizeof(crtc->mode)); 3122 xf86RotateDestroy(crtc); 3123 crtc->active = FALSE; 3124 } 3125 } 3126 if (pScrn->pScreen) 3127 xf86_crtc_notify(pScrn->pScreen); 3128 if (pScrn->ModeSet) 3129 pScrn->ModeSet(pScrn); 3130 if (pScrn->pScreen) { 3131 if (pScrn->pScreen->isGPU) 3132 xf86CursorResetCursor(pScrn->pScreen->current_master); 3133 else 3134 xf86CursorResetCursor(pScrn->pScreen); 3135 } 3136} 3137 3138#ifdef RANDR_12_INTERFACE 3139 3140#define EDID_ATOM_NAME "EDID" 3141 3142/** 3143 * Set the RandR EDID property 3144 */ 3145static void 3146xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len) 3147{ 3148 Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); 3149 3150 /* This may get called before the RandR resources have been created */ 3151 if (output->randr_output == NULL) 3152 return; 3153 3154 if (data_len != 0) { 3155 RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, 3156 PropModeReplace, data_len, data, FALSE, TRUE); 3157 } 3158 else { 3159 RRDeleteOutputProperty(output->randr_output, edid_atom); 3160 } 3161} 3162 3163#define TILE_ATOM_NAME "TILE" 3164/* changing this in the future could be tricky as people may hardcode 8 */ 3165#define TILE_PROP_NUM_ITEMS 8 3166static void 3167xf86OutputSetTileProperty(xf86OutputPtr output) 3168{ 3169 Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE); 3170 3171 /* This may get called before the RandR resources have been created */ 3172 if (output->randr_output == NULL) 3173 return; 3174 3175 if (output->tile_info.group_id != 0) { 3176 RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32, 3177 PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE); 3178 } 3179 else { 3180 RRDeleteOutputProperty(output->randr_output, tile_atom); 3181 } 3182} 3183 3184#endif 3185 3186/* Pull out a phyiscal size from a detailed timing if available. */ 3187struct det_phySize_parameter { 3188 xf86OutputPtr output; 3189 ddc_quirk_t quirks; 3190 Bool ret; 3191}; 3192 3193static void 3194handle_detailed_physical_size(struct detailed_monitor_section 3195 *det_mon, void *data) 3196{ 3197 struct det_phySize_parameter *p; 3198 3199 p = (struct det_phySize_parameter *) data; 3200 3201 if (p->ret == TRUE) 3202 return; 3203 3204 xf86DetTimingApplyQuirks(det_mon, p->quirks, 3205 p->output->MonInfo->features.hsize, 3206 p->output->MonInfo->features.vsize); 3207 if (det_mon->type == DT && 3208 det_mon->section.d_timings.h_size != 0 && 3209 det_mon->section.d_timings.v_size != 0) { 3210 /* some sanity checking for aspect ratio: 3211 assume any h / v (or v / h) > 2.4 to be bogus. 3212 This would even include cinemascope */ 3213 if (((det_mon->section.d_timings.h_size * 5) < 3214 (det_mon->section.d_timings.v_size * 12)) && 3215 ((det_mon->section.d_timings.v_size * 5) < 3216 (det_mon->section.d_timings.h_size * 12))) { 3217 p->output->mm_width = det_mon->section.d_timings.h_size; 3218 p->output->mm_height = det_mon->section.d_timings.v_size; 3219 p->ret = TRUE; 3220 } else 3221 xf86DrvMsg(p->output->scrn->scrnIndex, X_WARNING, 3222 "Output %s: Strange aspect ratio (%i/%i), " 3223 "consider adding a quirk\n", p->output->name, 3224 det_mon->section.d_timings.h_size, 3225 det_mon->section.d_timings.v_size); 3226 } 3227} 3228 3229Bool 3230xf86OutputParseKMSTile(const char *tile_data, int tile_length, 3231 struct xf86CrtcTileInfo *tile_info) 3232{ 3233 int ret; 3234 3235 ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d", 3236 &tile_info->group_id, 3237 &tile_info->flags, 3238 &tile_info->num_h_tile, 3239 &tile_info->num_v_tile, 3240 &tile_info->tile_h_loc, 3241 &tile_info->tile_v_loc, 3242 &tile_info->tile_h_size, 3243 &tile_info->tile_v_size); 3244 if (ret != 8) 3245 return FALSE; 3246 return TRUE; 3247} 3248 3249void 3250xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info) 3251{ 3252 if (tile_info) 3253 output->tile_info = *tile_info; 3254 else 3255 memset(&output->tile_info, 0, sizeof(output->tile_info)); 3256#ifdef RANDR_12_INTERFACE 3257 xf86OutputSetTileProperty(output); 3258#endif 3259} 3260 3261/** 3262 * Set the EDID information for the specified output 3263 */ 3264void 3265xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon) 3266{ 3267 ScrnInfoPtr scrn = output->scrn; 3268 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3269 Bool debug_modes = config->debug_modes || xf86Initialising; 3270 3271#ifdef RANDR_12_INTERFACE 3272 int size; 3273#endif 3274 3275 free(output->MonInfo); 3276 3277 output->MonInfo = edid_mon; 3278 output->mm_width = 0; 3279 output->mm_height = 0; 3280 3281 if (debug_modes) { 3282 xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", 3283 output->name); 3284 xf86PrintEDID(edid_mon); 3285 } 3286 3287 /* Set the DDC properties for the 'compat' output */ 3288 /* GPU screens don't have a root window */ 3289 if (output == xf86CompatOutput(scrn) && !scrn->is_gpu) 3290 xf86SetDDCproperties(scrn, edid_mon); 3291 3292#ifdef RANDR_12_INTERFACE 3293 /* Set the RandR output properties */ 3294 size = 0; 3295 if (edid_mon) { 3296 if (edid_mon->ver.version == 1) { 3297 size = 128; 3298 if (edid_mon->flags & EDID_COMPLETE_RAWDATA) 3299 size += edid_mon->no_sections * 128; 3300 } 3301 else if (edid_mon->ver.version == 2) 3302 size = 256; 3303 } 3304 xf86OutputSetEDIDProperty(output, edid_mon ? edid_mon->rawData : NULL, 3305 size); 3306#endif 3307 3308 if (edid_mon) { 3309 3310 struct det_phySize_parameter p; 3311 3312 p.output = output; 3313 p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex, edid_mon, FALSE); 3314 p.ret = FALSE; 3315 xf86ForEachDetailedBlock(edid_mon, handle_detailed_physical_size, &p); 3316 3317 /* if no mm size is available from a detailed timing, check the max size field */ 3318 if ((!output->mm_width || !output->mm_height) && 3319 (edid_mon->features.hsize && edid_mon->features.vsize)) { 3320 output->mm_width = edid_mon->features.hsize * 10; 3321 output->mm_height = edid_mon->features.vsize * 10; 3322 } 3323 } 3324} 3325 3326/** 3327 * Return the list of modes supported by the EDID information 3328 * stored in 'output' 3329 */ 3330DisplayModePtr 3331xf86OutputGetEDIDModes(xf86OutputPtr output) 3332{ 3333 ScrnInfoPtr scrn = output->scrn; 3334 xf86MonPtr edid_mon = output->MonInfo; 3335 3336 if (!edid_mon) 3337 return NULL; 3338 return xf86DDCGetModes(scrn->scrnIndex, edid_mon); 3339} 3340 3341/* maybe we should care about DDC1? meh. */ 3342xf86MonPtr 3343xf86OutputGetEDID(xf86OutputPtr output, I2CBusPtr pDDCBus) 3344{ 3345 ScrnInfoPtr scrn = output->scrn; 3346 xf86MonPtr mon; 3347 3348 mon = xf86DoEEDID(scrn, pDDCBus, TRUE); 3349 if (mon) 3350 xf86DDCApplyQuirks(scrn->scrnIndex, mon); 3351 3352 return mon; 3353} 3354 3355static const char *_xf86ConnectorNames[] = { 3356 "None", "VGA", "DVI-I", "DVI-D", 3357 "DVI-A", "Composite", "S-Video", 3358 "Component", "LFP", "Proprietary", 3359 "HDMI", "DisplayPort", 3360}; 3361 3362const char * 3363xf86ConnectorGetName(xf86ConnectorType connector) 3364{ 3365 return _xf86ConnectorNames[connector]; 3366} 3367 3368static void 3369x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 3370{ 3371 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 3372 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 3373 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 3374 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 3375 3376 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 3377 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 3378} 3379 3380static void 3381x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 3382{ 3383 if (crtc->enabled) { 3384 crtc_box->x1 = crtc->x; 3385 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 3386 crtc_box->y1 = crtc->y; 3387 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 3388 } 3389 else 3390 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 3391} 3392 3393static int 3394xf86_crtc_box_area(BoxPtr box) 3395{ 3396 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 3397} 3398 3399#ifdef XV 3400/* 3401 * Return the crtc covering 'box'. If two crtcs cover a portion of 3402 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 3403 * with greater coverage 3404 */ 3405 3406static xf86CrtcPtr 3407xf86_covering_crtc(ScrnInfoPtr pScrn, 3408 BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) 3409{ 3410 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3411 xf86CrtcPtr crtc, best_crtc; 3412 int coverage, best_coverage; 3413 int c; 3414 BoxRec crtc_box, cover_box; 3415 3416 best_crtc = NULL; 3417 best_coverage = 0; 3418 crtc_box_ret->x1 = 0; 3419 crtc_box_ret->x2 = 0; 3420 crtc_box_ret->y1 = 0; 3421 crtc_box_ret->y2 = 0; 3422 for (c = 0; c < xf86_config->num_crtc; c++) { 3423 crtc = xf86_config->crtc[c]; 3424 x86_crtc_box(crtc, &crtc_box); 3425 x86_crtc_box_intersect(&cover_box, &crtc_box, box); 3426 coverage = xf86_crtc_box_area(&cover_box); 3427 if (coverage && crtc == desired) { 3428 *crtc_box_ret = crtc_box; 3429 return crtc; 3430 } 3431 else if (coverage > best_coverage) { 3432 *crtc_box_ret = crtc_box; 3433 best_crtc = crtc; 3434 best_coverage = coverage; 3435 } 3436 } 3437 return best_crtc; 3438} 3439 3440/* 3441 * For overlay video, compute the relevant CRTC and 3442 * clip video to that. 3443 * 3444 * returning FALSE means there was a memory failure of some kind, 3445 * not that the video shouldn't be displayed 3446 */ 3447 3448Bool 3449xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, 3450 xf86CrtcPtr * crtc_ret, 3451 xf86CrtcPtr desired_crtc, 3452 BoxPtr dst, 3453 INT32 *xa, 3454 INT32 *xb, 3455 INT32 *ya, 3456 INT32 *yb, RegionPtr reg, INT32 width, INT32 height) 3457{ 3458 Bool ret; 3459 RegionRec crtc_region_local; 3460 RegionPtr crtc_region = reg; 3461 3462 if (crtc_ret) { 3463 BoxRec crtc_box; 3464 xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, 3465 desired_crtc, 3466 &crtc_box); 3467 3468 if (crtc) { 3469 RegionInit(&crtc_region_local, &crtc_box, 1); 3470 crtc_region = &crtc_region_local; 3471 RegionIntersect(crtc_region, crtc_region, reg); 3472 } 3473 *crtc_ret = crtc; 3474 } 3475 3476 ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 3477 crtc_region, width, height); 3478 3479 if (crtc_region != reg) 3480 RegionUninit(&crtc_region_local); 3481 3482 return ret; 3483} 3484#endif 3485 3486xf86_crtc_notify_proc_ptr 3487xf86_wrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr new) 3488{ 3489 if (xf86CrtcConfigPrivateIndex != -1) { 3490 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3491 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3492 xf86_crtc_notify_proc_ptr old; 3493 3494 old = config->xf86_crtc_notify; 3495 config->xf86_crtc_notify = new; 3496 return old; 3497 } 3498 return NULL; 3499} 3500 3501void 3502xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) 3503{ 3504 if (xf86CrtcConfigPrivateIndex != -1) { 3505 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3506 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3507 3508 config->xf86_crtc_notify = old; 3509 } 3510} 3511 3512void 3513xf86_crtc_notify(ScreenPtr screen) 3514{ 3515 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3516 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3517 3518 if (config->xf86_crtc_notify) 3519 config->xf86_crtc_notify(screen); 3520} 3521 3522Bool 3523xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) 3524{ 3525 if (xf86CrtcConfigPrivateIndex != -1) { 3526 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3527 xf86CrtcPtr crtc; 3528 3529 /* for multiple drivers loaded we need this */ 3530 if (!xf86_config) 3531 return FALSE; 3532 if (xf86_config->num_crtc == 0) 3533 return FALSE; 3534 crtc = xf86_config->crtc[0]; 3535 3536 return crtc->funcs->gamma_set != NULL; 3537 } 3538 3539 return FALSE; 3540} 3541 3542void 3543xf86ProviderSetup(ScrnInfoPtr scrn, 3544 const xf86ProviderFuncsRec *funcs, const char *name) 3545{ 3546 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 3547 3548 assert(!xf86_config->name); 3549 assert(name); 3550 3551 xf86_config->name = strdup(name); 3552 xf86_config->provider_funcs = funcs; 3553#ifdef RANDR_12_INTERFACE 3554 xf86_config->randr_provider = NULL; 3555#endif 3556} 3557 3558void 3559xf86DetachAllCrtc(ScrnInfoPtr scrn) 3560{ 3561 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 3562 int i; 3563 3564 for (i = 0; i < xf86_config->num_crtc; i++) { 3565 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3566 3567 if (crtc->randr_crtc) 3568 RRCrtcDetachScanoutPixmap(crtc->randr_crtc); 3569 3570 /* dpms off */ 3571 (*crtc->funcs->dpms) (crtc, DPMSModeOff); 3572 /* force a reset the next time its used */ 3573 crtc->randr_crtc->mode = NULL; 3574 crtc->mode.HDisplay = 0; 3575 crtc->x = crtc->y = 0; 3576 } 3577} 3578