xf86Crtc.c 97.8 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
    }

382 383
    free(adjusted_mode->name);
    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 431 432 433 434 435 436 437 438 439 440
/*
 * Output functions
 */

extern XF86ConfigPtr xf86configptr;

typedef enum {
    OPTION_PREFERRED_MODE,
    OPTION_POSITION,
    OPTION_BELOW,
    OPTION_RIGHT_OF,
    OPTION_ABOVE,
    OPTION_LEFT_OF,
    OPTION_ENABLE,
    OPTION_DISABLE,
    OPTION_MIN_CLOCK,
    OPTION_MAX_CLOCK,
    OPTION_IGNORE,
441
    OPTION_ROTATE,
442
    OPTION_PANNING,
443
    OPTION_PRIMARY,
444
    OPTION_DEFAULT_MODES,
445 446 447
} OutputOpts;

static OptionInfoRec xf86OutputOptions[] = {
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
    {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE},
    {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},
464 465
};

466 467 468 469 470
enum {
    OPTION_MODEDEBUG,
};

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

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

    if (!output->name)
482
        return;
483

484
    free(output->options);
485

486 487
    output->options = xnfalloc(sizeof(xf86OutputOptions));
    memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions));
488 489

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

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

    /* check to see if this output was enabled in the config file */
523 524 525 526
    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;
527 528
    }
    /* or if this output was disabled in the config file */
529 530 531 532
    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;
533
    }
534 535 536

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

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

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

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

static Rotation
563
xf86OutputInitialRotation(xf86OutputPtr output)
564
{
565 566 567
    char *rotate_name = xf86GetOptValString(output->options,
                                            OPTION_ROTATE);
    int i;
568

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

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

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

    if (name)
591
        len = strlen(name) + 1;
592
    else
593
        len = 0;
594

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

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

631
    xf86_config->output = outputs;
632

633 634 635 636
    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;
637
    }
638 639
    else {
        xf86_config->output[xf86_config->num_output] = output;
640 641 642 643
    }

    xf86_config->num_output++;

644 645 646
    return output;
}

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

652
    if (!newname)
653 654
        return FALSE;           /* so sorry... */

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

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

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

680 681
    (*output->funcs->destroy) (output);
    while (output->probed_modes)
682
        xf86DeleteMode(&output->probed_modes, output->probed_modes);
683
    for (o = 0; o < xf86_config->num_output; o++)
684 685 686 687 688 689 690
        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;
        }
691
    if (output->name && output->name != (char *) (output + 1))
692
        free(output->name);
693
    free(output);
694 695
}

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

    screen->CreateScreenResources = config->CreateScreenResources;

707 708 709 710 711
    if (!(*screen->CreateScreenResources) (screen))
        return FALSE;

    if (!xf86RandR12CreateScreenResources(screen))
        return FALSE;
712 713 714 715

    return TRUE;
}

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

726 727
    screen->CloseScreen = config->CloseScreen;

728
    xf86RotateCloseScreen(screen);
729

730 731 732 733
    xf86RandR12CloseScreen(screen);

    screen->CloseScreen(screen);

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

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

742
        crtc->randr_crtc = NULL;
743
    }
744 745
    /* detach any providers */
    if (config->randr_provider) {
746 747 748 749 750
        if (config->randr_provider->offload_sink) {
            DetachOffloadGPU(screen);
            config->randr_provider->offload_sink = NULL;
        }
        else if (config->randr_provider->output_source) {
751 752 753 754
            DetachOutputGPU(screen);
            config->randr_provider->output_source = NULL;
        }
        else if (screen->current_master)
755 756
            DetachUnboundGPU(screen);
    }
757
    return TRUE;
758 759
}

760 761 762
/*
 * Called at ScreenInit time to set up
 */
763 764 765 766 767
#ifdef RANDR_13_INTERFACE
int
#else
Bool
#endif
768
xf86CrtcScreenInit(ScreenPtr screen)
769
{
770
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
771 772
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
773 774

    /* Rotation */
775 776 777 778
    xf86DrvMsg(scrn->scrnIndex, X_INFO,
               "RandR 1.2 enabled, ignore the following RandR disabled message.\n");
    xf86DisableRandR();         /* Disable old RandR extension support */
    xf86RandR12Init(screen);
779 780

    /* support all rotations if every crtc has the shadow alloc funcs */
781 782 783 784 785
    for (c = 0; c < config->num_crtc; c++) {
        xf86CrtcPtr crtc = config->crtc[c];

        if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create)
            break;
786
    }
787 788 789 790 791 792 793 794 795
    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);
796
    }
797

798 799 800
    /* Wrap CreateScreenResources so we can initialize the RandR code */
    config->CreateScreenResources = screen->CreateScreenResources;
    screen->CreateScreenResources = xf86CrtcCreateScreenResources;
801 802 803

    config->CloseScreen = screen->CloseScreen;
    screen->CloseScreen = xf86CrtcCloseScreen;
804 805 806

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

808
#ifdef XFreeXDGA
Keith Packard's avatar
Keith Packard committed
809
    _xf86_di_dga_init_internal(screen);
810
#endif
811 812 813
#ifdef RANDR_13_INTERFACE
    return RANDR_INTERFACE_VERSION;
#else
814
    return TRUE;
815
#endif
816 817
}

818
static DisplayModePtr
819 820 821 822 823 824 825 826
xf86DefaultMode(xf86OutputPtr output, int width, int height)
{
    DisplayModePtr target_mode = NULL;
    DisplayModePtr mode;
    int target_diff = 0;
    int target_preferred = 0;
    int mm_height;

827 828
    mm_height = output->mm_height;
    if (!mm_height)
829
        mm_height = (768 * 25.4) / DEFAULT_DPI;
830
    /*
831
     * Pick a mode closest to DEFAULT_DPI
832
     */
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
    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;
        }
853 854 855 856 857
    }
    return target_mode;
}

static DisplayModePtr
858 859 860 861 862 863 864 865
xf86ClosestMode(xf86OutputPtr output,
                DisplayModePtr match, Rotation match_rotation,
                int width, int height)
{
    DisplayModePtr target_mode = NULL;
    DisplayModePtr mode;
    int target_diff = 0;

866 867 868
    /*
     * Pick a mode closest to the specified mode
     */
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
    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;
        }
893 894 895 896
    }
    return target_mode;
}

897
static DisplayModePtr
898
xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height)
899
{
900
    DisplayModePtr mode;
901

902 903 904 905
    for (mode = output->probed_modes; mode; mode = mode->next) {
        if (xf86ModeWidth(mode, output->initial_rotation) > width ||
            xf86ModeHeight(mode, output->initial_rotation) > height)
            continue;
906

907 908
        if (mode->type & M_T_PREFERRED)
            return mode;
909
    }
910 911 912 913
    return NULL;
}

static DisplayModePtr
914
xf86OutputHasUserPreferredMode(xf86OutputPtr output)
915 916 917 918
{
    DisplayModePtr mode, first = output->probed_modes;

    for (mode = first; mode && mode->next != first; mode = mode->next)
919 920
        if (mode->type & M_T_USERPREF)
            return mode;
921 922

    return NULL;
923 924 925
}

static int
926 927 928 929 930 931 932 933 934 935 936 937 938 939
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;
    xf86CrtcPtr best_crtc;
    int best_score;
    int score;
    int my_score;

940
    if (n == config->num_output)
941
        return 0;
942
    output = config->output[n];
943

944 945 946 947 948
    /*
     * Compute score with this output disabled
     */
    best_crtcs[n] = NULL;
    best_crtc = NULL;
949
    best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height);
950
    if (modes[n] == NULL)
951 952 953
        return best_score;

    crtcs = malloc(config->num_output * sizeof(xf86CrtcPtr));
954
    if (!crtcs)
955
        return best_score;
956 957 958 959

    my_score = 1;
    /* Score outputs that are known to be connected higher */
    if (output->status == XF86OutputStatusConnected)
960
        my_score++;
961
    /* Score outputs with preferred modes higher */
962 963
    if (xf86OutputHasPreferredMode(output, width, height))
        my_score++;
964 965 966 967 968
    /*
     * Select a crtc for this output and
     * then attempt to configure the remaining
     * outputs
     */
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 997 998 999 1000 1001 1002 1003 1004 1005
    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
             */
            if (xf86ModesEqual(modes[o], modes[n]) &&
                config->output[o]->initial_rotation ==
                config->output[n]->initial_rotation &&
                config->output[o]->initial_x == config->output[n]->initial_x &&
                config->output[o]->initial_y == config->output[n]->initial_y) {
                if ((output->possible_clones & (1 << o)) == 0)
                    continue;   /* nope, try next CRTC */
            }
            else
                continue;       /* different modes, can't clone */
        }
        crtcs[n] = crtc;
        memcpy(crtcs, best_crtcs, n * sizeof(xf86CrtcPtr));