xf86Crtc.c 102 KB
Newer Older
1 2
/*
 * Copyright © 2006 Keith Packard
3
 * Copyright © 2008 Red Hat, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
26 27 28 29
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
30 31 32 33 34 35 36 37 38 39
#endif

#include <stddef.h>
#include <string.h>
#include <stdio.h>

#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
40
#include "xf86Priv.h"
41 42
#include "xf86RandR12.h"
#include "X11/extensions/render.h"
Peter Hutterer's avatar
Peter Hutterer committed
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 52
#define NO_OUTPUT_DEFAULT_WIDTH 1024
#define NO_OUTPUT_DEFAULT_HEIGHT 768
53 54 55 56
/*
 * Initialize xf86CrtcConfig structure
 */

57
int xf86CrtcConfigPrivateIndex = -1;
58

59
void
60
xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs)
61
{
62 63
    xf86CrtcConfigPtr config;

64
    if (xf86CrtcConfigPrivateIndex == -1)
65 66
        xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
    config = xnfcalloc(1, sizeof(xf86CrtcConfigRec));
67 68

    config->funcs = funcs;
69
    config->compat_output = -1;
70

71 72
    scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config;
}
73

74
void
75 76
xf86CrtcSetSizeRange(ScrnInfoPtr scrn,
                     int minWidth, int minHeight, int maxWidth, int maxHeight)
77
{
78
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
79 80 81 82 83 84 85 86 87 88

    config->minWidth = minWidth;
    config->minHeight = minHeight;
    config->maxWidth = maxWidth;
    config->maxHeight = maxHeight;
}

/*
 * Crtc functions
 */
89
xf86CrtcPtr
90
xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs)
91
{
92 93
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CrtcPtr crtc, *crtcs;
94

95
    crtc = calloc(sizeof(xf86CrtcRec), 1);
96
    if (!crtc)
97
        return NULL;
98
    crtc->version = XF86_CRTC_VERSION;
99 100 101 102 103 104 105
    crtc->scrn = scrn;
    crtc->funcs = funcs;
#ifdef RANDR_12_INTERFACE
    crtc->randr_crtc = NULL;
#endif
    crtc->rotation = RR_Rotate_0;
    crtc->desiredRotation = RR_Rotate_0;
106 107 108
    pixman_transform_init_identity(&crtc->crtc_to_framebuffer);
    pixman_f_transform_init_identity(&crtc->f_crtc_to_framebuffer);
    pixman_f_transform_init_identity(&crtc->f_framebuffer_to_crtc);
109 110 111 112 113 114
    crtc->filter = NULL;
    crtc->params = NULL;
    crtc->nparams = 0;
    crtc->filter_width = 0;
    crtc->filter_height = 0;
    crtc->transform_in_use = FALSE;
115 116
    crtc->transformPresent = FALSE;
    crtc->desiredTransformPresent = FALSE;
117
    memset(&crtc->bounds, '\0', sizeof(crtc->bounds));
118

119 120
    /* Preallocate gamma at a sensible size. */
    crtc->gamma_size = 256;
121
    crtc->gamma_red = malloc(3 * crtc->gamma_size * sizeof(CARD16));
122
    if (!crtc->gamma_red) {
123 124
        free(crtc);
        return NULL;
125
    }
126 127 128
    crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
    crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;

129
    if (xf86_config->crtc)
130 131
        crtcs = realloc(xf86_config->crtc,
                        (xf86_config->num_crtc + 1) * sizeof(xf86CrtcPtr));
132
    else
133 134 135 136 137
        crtcs = malloc((xf86_config->num_crtc + 1) * sizeof(xf86CrtcPtr));
    if (!crtcs) {
        free(crtc->gamma_red);
        free(crtc);
        return NULL;
138 139 140 141 142 143
    }
    xf86_config->crtc = crtcs;
    xf86_config->crtc[xf86_config->num_crtc++] = crtc;
    return crtc;
}

144
void
145
xf86CrtcDestroy(xf86CrtcPtr crtc)
146
{
147 148 149
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    int c;

150 151
    (*crtc->funcs->destroy) (crtc);
    for (c = 0; c < xf86_config->num_crtc; c++)
152 153 154 155 156 157 158
        if (xf86_config->crtc[c] == crtc) {
            memmove(&xf86_config->crtc[c],
                    &xf86_config->crtc[c + 1],
                    ((xf86_config->num_crtc - (c + 1)) * sizeof(void *)));
            xf86_config->num_crtc--;
            break;
        }
159
    free(crtc->params);
160
    free(crtc->gamma_red);
161
    free(crtc);
162 163 164 165 166 167
}

/**
 * Return whether any outputs are connected to the specified pipe
 */

168
Bool
169
xf86CrtcInUse(xf86CrtcPtr crtc)
170
{
171 172 173 174
    ScrnInfoPtr pScrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    int o;

175
    for (o = 0; o < xf86_config->num_output; o++)
176 177
        if (xf86_config->output[o]->crtc == crtc)
            return TRUE;
178 179 180
    return FALSE;
}

181
void
182
xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen)
183
{
184 185
    int subpixel_order = SubPixelUnknown;
    Bool has_none = FALSE;
186
    ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
187 188
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c, o;
189

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];

        for (o = 0; o < xf86_config->num_output; o++) {
            xf86OutputPtr output = xf86_config->output[o];

            if (output->crtc == crtc) {
                switch (output->subpixel_order) {
                case SubPixelNone:
                    has_none = TRUE;
                    break;
                case SubPixelUnknown:
                    break;
                default:
                    subpixel_order = output->subpixel_order;
                    break;
                }
            }
            if (subpixel_order != SubPixelUnknown)
                break;
        }
        if (subpixel_order != SubPixelUnknown) {
            static const int circle[4] = {
                SubPixelHorizontalRGB,
                SubPixelVerticalRGB,
                SubPixelHorizontalBGR,
                SubPixelVerticalBGR,
            };
            int rotate;
            int c;

            for (rotate = 0; rotate < 4; rotate++)
                if (crtc->rotation & (1 << rotate))
                    break;
            for (c = 0; c < 4; c++)
                if (circle[c] == subpixel_order)
                    break;
            c = (c + rotate) & 0x3;
            if ((crtc->rotation & RR_Reflect_X) && !(c & 1))
                c ^= 2;
            if ((crtc->rotation & RR_Reflect_Y) && (c & 1))
                c ^= 2;
            subpixel_order = circle[c];
            break;
        }
235 236
    }
    if (subpixel_order == SubPixelUnknown && has_none)
237 238
        subpixel_order = SubPixelNone;
    PictureSetSubpixelOrder(pScreen, subpixel_order);
239 240
}

241 242 243
/**
 * Sets the given video mode on the given crtc
 */
244
Bool
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode,
                         Rotation rotation, RRTransformPtr transform, int x,
                         int y)
{
    ScrnInfoPtr scrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int i;
    Bool ret = FALSE;
    Bool didLock = FALSE;
    DisplayModePtr adjusted_mode;
    DisplayModeRec saved_mode;
    int saved_x, saved_y;
    Rotation saved_rotation;
    RRTransformRec saved_transform;
    Bool saved_transform_present;

    crtc->enabled = xf86CrtcInUse(crtc);
262

263
    /* We only hit this if someone explicitly sends a "disabled" modeset. */
264 265 266 267
    if (!crtc->enabled) {
        /* Check everything for stuff that should be off. */
        xf86DisableUnusedFunctions(scrn);
        return TRUE;
268 269
    }

270 271
    adjusted_mode = xf86DuplicateMode(mode);

272 273 274 275
    saved_mode = crtc->mode;
    saved_x = crtc->x;
    saved_y = crtc->y;
    saved_rotation = crtc->rotation;
276
    if (crtc->transformPresent) {
277 278
        RRTransformInit(&saved_transform);
        RRTransformCopy(&saved_transform, &crtc->transform);
279
    }
280 281
    saved_transform_present = crtc->transformPresent;

282 283 284
    /* Update crtc values up front so the driver can rely on them for mode
     * setting.
     */
285 286 287 288 289
    crtc->mode = *mode;
    crtc->x = x;
    crtc->y = y;
    crtc->rotation = rotation;
    if (transform) {
290 291 292 293 294
        RRTransformCopy(&crtc->transform, transform);
        crtc->transformPresent = TRUE;
    }
    else
        crtc->transformPresent = FALSE;
295

296
    if (crtc->funcs->set_mode_major) {
297 298
        ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y);
        goto done;
299 300
    }

301
    didLock = crtc->funcs->lock(crtc);
302 303 304 305 306
    /* Pass our mode to the outputs and the CRTC to give them a chance to
     * adjust it according to limitations or output properties, and also
     * a chance to reject the mode entirely.
     */
    for (i = 0; i < xf86_config->num_output; i++) {
307
        xf86OutputPtr output = xf86_config->output[i];
308

309 310
        if (output->crtc != crtc)
            continue;
311

312 313 314
        if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
            goto done;
        }
315 316
    }

317
    if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) {
318
        goto done;
319 320
    }

321 322
    if (!xf86CrtcRotate(crtc))
        goto done;
323

Dave Airlie's avatar
Dave Airlie committed
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 329
        if (output->crtc != crtc)
            continue;
330

331 332
        /* Disable the output as the first thing we do. */
        output->funcs->prepare(output);
333 334
    }

Dave Airlie's avatar
Dave Airlie committed
335
    crtc->funcs->prepare(crtc);
336 337 338 339

    /* Set up the DPLL and any output state that needs to adjust or depend
     * on the DPLL.
     */
340
    crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y);
341 342 343 344 345
    for (i = 0; i < xf86_config->num_output; i++) {
        xf86OutputPtr output = xf86_config->output[i];

        if (output->crtc == crtc)
            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 351
        crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
                               crtc->gamma_blue, crtc->gamma_size);
352

353
    /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
Dave Airlie's avatar
Dave Airlie committed
354
    crtc->funcs->commit(crtc);
355 356 357 358 359
    for (i = 0; i < xf86_config->num_output; i++) {
        xf86OutputPtr output = xf86_config->output[i];

        if (output->crtc == crtc)
            output->funcs->commit(output);
360 361 362
    }

    ret = TRUE;
363

364
 done:
365
    if (ret) {
366 367 368 369 370 371 372 373 374 375 376 377 378 379
        crtc->active = TRUE;
        if (scrn->pScreen)
            xf86CrtcSetScreenSubpixelOrder(scrn->pScreen);
        if (scrn->ModeSet)
            scrn->ModeSet(scrn);
    }
    else {
        crtc->x = saved_x;
        crtc->y = saved_y;
        crtc->rotation = saved_rotation;
        crtc->mode = saved_mode;
        if (saved_transform_present)
            RRTransformCopy(&crtc->transform, &saved_transform);
        crtc->transformPresent = saved_transform_present;
380 381
    }

Keith Packard's avatar
Keith Packard committed
382
    free((void *) adjusted_mode->name);
383
    free(adjusted_mode);
384

385
    if (didLock)
386
        crtc->funcs->unlock(crtc);
387 388 389 390

    return ret;
}

391 392 393 394 395
/**
 * Sets the given video mode on the given crtc, but without providing
 * a transform
 */
Bool
396 397
xf86CrtcSetMode(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation,
                int x, int y)
398
{
399
    return xf86CrtcSetModeTransform(crtc, mode, rotation, NULL, x, y);
400 401
}

Matthias Hopf's avatar
Matthias Hopf committed
402 403 404
/**
 * Pans the screen, does not change the mode
 */
405
void
406
xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y)
Matthias Hopf's avatar
Matthias Hopf committed
407
{
408 409 410 411 412
    ScrnInfoPtr scrn = crtc->scrn;

    crtc->x = x;
    crtc->y = y;
    if (crtc->funcs->set_origin) {
413 414 415 416 417
        if (!xf86CrtcRotate(crtc))
            return;
        crtc->funcs->set_origin(crtc, x, y);
        if (scrn->ModeSet)
            scrn->ModeSet(scrn);
418
    }
419
    else
420
        xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, x, y);
Matthias Hopf's avatar
Matthias Hopf committed
421 422
}

423 424 425 426 427 428 429 430
/*
 * Output functions
 */

extern XF86ConfigPtr xf86configptr;

typedef enum {
    OPTION_PREFERRED_MODE,
431
    OPTION_ZOOM_MODES,
432 433 434 435 436 437 438 439 440 441
    OPTION_POSITION,
    OPTION_BELOW,
    OPTION_RIGHT_OF,
    OPTION_ABOVE,
    OPTION_LEFT_OF,
    OPTION_ENABLE,
    OPTION_DISABLE,
    OPTION_MIN_CLOCK,
    OPTION_MAX_CLOCK,
    OPTION_IGNORE,
442
    OPTION_ROTATE,
443
    OPTION_PANNING,
444
    OPTION_PRIMARY,
445
    OPTION_DEFAULT_MODES,
446 447 448
} OutputOpts;

static OptionInfoRec xf86OutputOptions[] = {
449
    {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE},
450
    {OPTION_ZOOM_MODES, "ZoomModes", OPTV_STRING, {0}, FALSE },
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
    {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE},
    {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE},
    {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE},
    {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE},
    {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE},
    {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE},
    {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE},
    {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE},
    {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE},
    {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE},
    {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE},
    {-1, NULL, OPTV_NONE, {0}, FALSE},
466 467
};

468 469 470 471 472
enum {
    OPTION_MODEDEBUG,
};

static OptionInfoRec xf86DeviceOptions[] = {
473 474
    {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
    {-1, NULL, OPTV_NONE, {0}, FALSE},
475 476
};

477
static void
478
xf86OutputSetMonitor(xf86OutputPtr output)
479
{
480 481
    char *option_name;
    const char *monitor;
482 483

    if (!output->name)
484
        return;
485

486
    free(output->options);
487

488 489
    output->options = xnfalloc(sizeof(xf86OutputOptions));
    memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions));
490 491

    XNFasprintf(&option_name, "monitor-%s", output->name);
492
    monitor = xf86findOptionValue(output->scrn->options, option_name);
493
    if (!monitor)
494
        monitor = output->name;
495
    else
496
        xf86MarkOptionUsedByName(output->scrn->options, option_name);
497
    free(option_name);
498 499
    output->conf_monitor = xf86findMonitor(monitor,
                                           xf86configptr->conf_monitor_lst);
500 501 502 503
    /*
     * Find the monitor section of the screen and use that
     */
    if (!output->conf_monitor && output->use_screen_monitor)
504 505 506 507 508 509 510 511 512
        output->conf_monitor = xf86findMonitor(output->scrn->monitor->id,
                                               xf86configptr->conf_monitor_lst);
    if (output->conf_monitor) {
        xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                   "Output %s using monitor section %s\n",
                   output->name, output->conf_monitor->mon_identifier);
        xf86ProcessOptions(output->scrn->scrnIndex,
                           output->conf_monitor->mon_option_lst,
                           output->options);
513 514
    }
    else
515 516
        xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                   "Output %s has no monitor section\n", output->name);
517 518 519
}

static Bool
520
xf86OutputEnabled(xf86OutputPtr output, Bool strict)
521
{
522
    Bool enable, disable;
523 524

    /* check to see if this output was enabled in the config file */
525 526 527 528
    if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable) {
        xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                   "Output %s enabled by config file\n", output->name);
        return TRUE;
529 530
    }
    /* or if this output was disabled in the config file */
531 532 533 534
    if (xf86GetOptValBool(output->options, OPTION_DISABLE, &disable) && disable) {
        xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
                   "Output %s disabled by config file\n", output->name);
        return FALSE;
535
    }
536 537 538

    /* If not, try to only light up the ones we know are connected */
    if (strict) {
539
        enable = output->status == XF86OutputStatusConnected;
540 541 542
    }
    /* But if that fails, try to light up even outputs we're unsure of */
    else {
543
        enable = output->status != XF86OutputStatusDisconnected;
544 545
    }

546 547
    xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
               "Output %s %sconnected\n", output->name, enable ? "" : "dis");
548
    return enable;
549 550 551
}

static Bool
552
xf86OutputIgnored(xf86OutputPtr output)
553
{
554
    return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE);
555 556
}

557
static const char *direction[4] = {
558 559 560
    "normal",
    "left",
    "inverted",
561 562 563 564
    "right"
};

static Rotation
565
xf86OutputInitialRotation(xf86OutputPtr output)
566
{
Keith Packard's avatar
Keith Packard committed
567 568
    const char *rotate_name = xf86GetOptValString(output->options,
                                                  OPTION_ROTATE);
569
    int i;
570

571
    if (!rotate_name) {
572 573 574
        if (output->initial_rotation)
            return output->initial_rotation;
        return RR_Rotate_0;
575
    }
576

577
    for (i = 0; i < 4; i++)
578 579
        if (xf86nameCompare(direction[i], rotate_name) == 0)
            return 1 << i;
580 581 582
    return RR_Rotate_0;
}

583
xf86OutputPtr
584 585
xf86OutputCreate(ScrnInfoPtr scrn,
                 const xf86OutputFuncsRec * funcs, const char *name)
586
{
587 588 589 590
    xf86OutputPtr output, *outputs;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int len;
    Bool primary;
591 592

    if (name)
593
        len = strlen(name) + 1;
594
    else
595
        len = 0;
596

597
    output = calloc(sizeof(xf86OutputRec) + len, 1);
598
    if (!output)
599
        return NULL;
600 601
    output->scrn = scrn;
    output->funcs = funcs;
602 603 604
    if (name) {
        output->name = (char *) (output + 1);
        strcpy(output->name, name);
605 606
    }
    output->subpixel_order = SubPixelUnknown;
607 608 609 610
    /*
     * Use the old per-screen monitor section for the first output
     */
    output->use_screen_monitor = (xf86_config->num_output == 0);
611 612 613
#ifdef RANDR_12_INTERFACE
    output->randr_output = NULL;
#endif
614 615 616 617 618 619 620 621
    if (name) {
        xf86OutputSetMonitor(output);
        if (xf86OutputIgnored(output)) {
            free(output);
            return FALSE;
        }
    }

622
    if (xf86_config->output)
623 624 625
        outputs = realloc(xf86_config->output,
                          (xf86_config->num_output +
                           1) * sizeof(xf86OutputPtr));
626
    else
627 628 629 630
        outputs = malloc((xf86_config->num_output + 1) * sizeof(xf86OutputPtr));
    if (!outputs) {
        free(output);
        return NULL;
631
    }
632

633
    xf86_config->output = outputs;
634

635 636 637 638
    if (xf86GetOptValBool(output->options, OPTION_PRIMARY, &primary) && primary) {
        memmove(xf86_config->output + 1, xf86_config->output,
                xf86_config->num_output * sizeof(xf86OutputPtr));
        xf86_config->output[0] = output;
639
    }
640 641
    else {
        xf86_config->output[xf86_config->num_output] = output;
642 643 644 645
    }

    xf86_config->num_output++;

646 647 648
    return output;
}

649
Bool
650
xf86OutputRename(xf86OutputPtr output, const char *name)
651
{
652 653
    char *newname = strdup(name);

654
    if (!newname)
655 656
        return FALSE;           /* so sorry... */

657
    if (output->name && output->name != (char *) (output + 1))
658
        free(output->name);
659
    output->name = newname;
660 661 662
    xf86OutputSetMonitor(output);
    if (xf86OutputIgnored(output))
        return FALSE;
663 664 665
    return TRUE;
}

666
void
667
xf86OutputUseScreenMonitor(xf86OutputPtr output, Bool use_screen_monitor)
668
{
669 670 671
    if (use_screen_monitor != output->use_screen_monitor) {
        output->use_screen_monitor = use_screen_monitor;
        xf86OutputSetMonitor(output);
672 673 674
    }
}

675
void
676
xf86OutputDestroy(xf86OutputPtr output)
677
{
678 679 680 681
    ScrnInfoPtr scrn = output->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int o;

682 683
    (*output->funcs->destroy) (output);
    while (output->probed_modes)
684
        xf86DeleteMode(&output->probed_modes, output->probed_modes);
685
    for (o = 0; o < xf86_config->num_output; o++)
686 687 688 689 690 691 692
        if (xf86_config->output[o] == output) {
            memmove(&xf86_config->output[o],
                    &xf86_config->output[o + 1],
                    ((xf86_config->num_output - (o + 1)) * sizeof(void *)));
            xf86_config->num_output--;
            break;
        }
693
    if (output->name && output->name != (char *) (output + 1))
694
        free(output->name);
695
    free(output);
696 697
}

698 699 700 701
/*
 * Called during CreateScreenResources to hook up RandR
 */
static Bool
702
xf86CrtcCreateScreenResources(ScreenPtr screen)
703
{
704
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
705
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
706 707 708

    screen->CreateScreenResources = config->CreateScreenResources;

709 710 711 712 713
    if (!(*screen->CreateScreenResources) (screen))
        return FALSE;

    if (!xf86RandR12CreateScreenResources(screen))
        return FALSE;
714 715 716 717

    return TRUE;
}

718 719 720 721
/*
 * Clean up config on server reset
 */
static Bool
722
xf86CrtcCloseScreen(ScreenPtr screen)
723
{
724
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
725 726 727
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    int o, c;

728 729
    screen->CloseScreen = config->CloseScreen;

730
    xf86RotateCloseScreen(screen);
731

732 733 734 735
    xf86RandR12CloseScreen(screen);

    screen->CloseScreen(screen);

736 737
    for (o = 0; o < config->num_output; o++) {
        xf86OutputPtr output = config->output[o];
738

739
        output->randr_output = NULL;
740
    }
741 742
    for (c = 0; c < config->num_crtc; c++) {
        xf86CrtcPtr crtc = config->crtc[c];
743

744
        crtc->randr_crtc = NULL;
745
    }
746 747
    /* detach any providers */
    if (config->randr_provider) {
Dave Airlie's avatar
Dave Airlie committed
748 749
        RRProviderDestroy(config->randr_provider);
        config->randr_provider = NULL;
750
    }
751
    return TRUE;
752 753
}

754 755 756
/*
 * Called at ScreenInit time to set up
 */
757 758 759 760 761
#ifdef RANDR_13_INTERFACE
int
#else
Bool
#endif
762
xf86CrtcScreenInit(ScreenPtr screen)
763
{
764
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
765 766
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
767 768

    /* Rotation */
769 770 771 772
    xf86DrvMsg(scrn->scrnIndex, X_INFO,
               "RandR 1.2 enabled, ignore the following RandR disabled message.\n");
    xf86DisableRandR();         /* Disable old RandR extension support */
    xf86RandR12Init(screen);
773 774

    /* support all rotations if every crtc has the shadow alloc funcs */
775 776 777 778 779
    for (c = 0; c < config->num_crtc; c++) {
        xf86CrtcPtr crtc = config->crtc[c];

        if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create)
            break;
780
    }
781 782 783 784 785 786 787 788 789
    if (c == config->num_crtc) {
        xf86RandR12SetRotations(screen, RR_Rotate_0 | RR_Rotate_90 |
                                RR_Rotate_180 | RR_Rotate_270 |
                                RR_Reflect_X | RR_Reflect_Y);
        xf86RandR12SetTransformSupport(screen, TRUE);
    }
    else {
        xf86RandR12SetRotations(screen, RR_Rotate_0);
        xf86RandR12SetTransformSupport(screen, FALSE);
790
    }
791

792 793 794
    /* Wrap CreateScreenResources so we can initialize the RandR code */
    config->CreateScreenResources = screen->CreateScreenResources;
    screen->CreateScreenResources = xf86CrtcCreateScreenResources;
795 796 797

    config->CloseScreen = screen->CloseScreen;
    screen->CloseScreen = xf86CrtcCloseScreen;
798 799 800

    /* This might still be marked wrapped from a previous generation */
    config->BlockHandler = NULL;
801

802
#ifdef XFreeXDGA
Keith Packard's avatar
Keith Packard committed
803
    _xf86_di_dga_init_internal(screen);
804
#endif
805 806 807
#ifdef RANDR_13_INTERFACE
    return RANDR_INTERFACE_VERSION;
#else
808
    return TRUE;
809
#endif
810 811
}

812
static DisplayModePtr
813 814 815 816 817 818 819 820
xf86DefaultMode(xf86OutputPtr output, int width, int height)
{
    DisplayModePtr target_mode = NULL;
    DisplayModePtr mode;
    int target_diff = 0;
    int target_preferred = 0;
    int mm_height;

821 822
    mm_height = output->mm_height;
    if (!mm_height)
823
        mm_height = (768 * 25.4) / DEFAULT_DPI;
824
    /*
825
     * Pick a mode closest to DEFAULT_DPI
826
     */
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
    for (mode = output->probed_modes; mode; mode = mode->next) {
        int dpi;
        int preferred = (((mode->type & M_T_PREFERRED) != 0) +
                         ((mode->type & M_T_USERPREF) != 0));
        int diff;

        if (xf86ModeWidth(mode, output->initial_rotation) > width ||
            xf86ModeHeight(mode, output->initial_rotation) > height)
            continue;

        /* yes, use VDisplay here, not xf86ModeHeight */
        dpi = (mode->VDisplay * 254) / (mm_height * 10);
        diff = dpi - DEFAULT_DPI;
        diff = diff < 0 ? -diff : diff;
        if (target_mode == NULL || (preferred > target_preferred) ||
            (preferred == target_preferred && diff < target_diff)) {
            target_mode = mode;
            target_diff = diff;
            target_preferred = preferred;
        }
847 848 849 850 851
    }
    return target_mode;
}

static DisplayModePtr
852 853 854 855 856 857 858 859
xf86ClosestMode(xf86OutputPtr output,
                DisplayModePtr match, Rotation match_rotation,
                int width, int height)
{
    DisplayModePtr target_mode = NULL;
    DisplayModePtr mode;
    int target_diff = 0;

860 861 862
    /*
     * Pick a mode closest to the specified mode
     */
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
    for (mode = output->probed_modes; mode; mode = mode->next) {
        int dx, dy;
        int diff;

        if (xf86ModeWidth(mode, output->initial_rotation) > width ||
            xf86ModeHeight(mode, output->initial_rotation) > height)
            continue;

        /* exact matches are preferred */
        if (output->initial_rotation == match_rotation &&
            xf86ModesEqual(mode, match))
            return mode;

        dx = xf86ModeWidth(match, match_rotation) - xf86ModeWidth(mode,
                                                                  output->
                                                                  initial_rotation);
        dy = xf86ModeHeight(match, match_rotation) - xf86ModeHeight(mode,
                                                                    output->
                                                                    initial_rotation);
        diff = dx * dx + dy * dy;
        if (target_mode == NULL || diff < target_diff) {
            target_mode = mode;
            target_diff = diff;
        }
887 888 889 890
    }
    return target_mode;
}

891
static DisplayModePtr
892
xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height)
893
{
894
    DisplayModePtr mode;
895

896 897 898 899
    for (mode = output->probed_modes; mode; mode = mode->next) {
        if (xf86ModeWidth(mode, output->initial_rotation) > width ||
            xf86ModeHeight(mode, output->initial_rotation) > height)
            continue;
900

901 902
        if (mode->type & M_T_PREFERRED)
            return mode;
903
    }
904 905 906 907
    return NULL;
}

static DisplayModePtr
908
xf86OutputHasUserPreferredMode(xf86OutputPtr output)
909 910 911 912
{
    DisplayModePtr mode, first = output->probed_modes;

    for (mode = first; mode && mode->next != first; mode = mode->next)
913 914
        if (mode->type & M_T_USERPREF)
            return mode;
915 916

    return NULL;
917 918 919
}

static int
920 921 922 923 924 925 926 927 928 929 930 931 932
xf86PickCrtcs(ScrnInfoPtr scrn,
              xf86CrtcPtr * best_crtcs,
              DisplayModePtr * modes, int n, int width, int height)
{
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    int c, o;
    xf86OutputPtr output;
    xf86CrtcPtr crtc;
    xf86CrtcPtr *crtcs;
    int best_score;
    int score;
    int my_score;

933
    if (n == config->num_output)
934
        return 0;
935
    output = config->output[n];
936

937 938 939 940
    /*
     * Compute score with this output disabled
     */
    best_crtcs[n] = NULL;
941
    best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height);
942
    if (modes[n] == NULL)
943 944 945
        return best_score;

    crtcs = malloc(config->num_output * sizeof(xf86CrtcPtr));
946
    if (!crtcs)
947
        return best_score;
948 949 950 951

    my_score = 1;
    /* Score outputs that are known to be connected higher */
    if (output->status == XF86OutputStatusConnected)
952
        my_score++;
953
    /* Score outputs with preferred modes higher */
954 955
    if (xf86OutputHasPreferredMode(output, width, height))
        my_score++;
956 957 958 959 960
    /*
     * Select a crtc for this output and
     * then attempt to configure the remaining
     * outputs
     */
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
    for (c = 0; c < config->num_crtc; c++) {
        if ((output->possible_crtcs & (1 << c)) == 0)
            continue;

        crtc = config->crtc[c];
        /*
         * Check to see if some other output is
         * using this crtc
         */
        for (o = 0; o < n; o++)
            if (best_crtcs[o] == crtc)
                break;
        if (o < n) {
            /*
             * If the two outputs desire the same mode,
             * see if they can be cloned
             */