xf86Crtc.c 103 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 26 27 28 29 30 31 32 33 34 35
 *
 * 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>
#endif

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

#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
36
#include "xf86Priv.h"
37 38
#include "xf86RandR12.h"
#include "X11/extensions/render.h"
Peter Hutterer's avatar
Peter Hutterer committed
39
#include "X11/extensions/dpmsconst.h"
40
#include "X11/Xatom.h"
41
#include "picturestr.h"
42

43
#ifdef XV
44
#include "xf86xv.h"
45
#endif
46

47 48
#define NO_OUTPUT_DEFAULT_WIDTH 1024
#define NO_OUTPUT_DEFAULT_HEIGHT 768
49 50 51 52
/*
 * Initialize xf86CrtcConfig structure
 */

53
int xf86CrtcConfigPrivateIndex = -1;
54

55
void
56
xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs)
57
{
58 59
    xf86CrtcConfigPtr config;

60
    if (xf86CrtcConfigPrivateIndex == -1)
61 62
        xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
    config = xnfcalloc(1, sizeof(xf86CrtcConfigRec));
63 64

    config->funcs = funcs;
65
    config->compat_output = -1;
66

67 68
    scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config;
}
69

70
void
71 72
xf86CrtcSetSizeRange(ScrnInfoPtr scrn,
                     int minWidth, int minHeight, int maxWidth, int maxHeight)
73
{
74
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
75 76 77 78 79 80 81 82 83 84

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

/*
 * Crtc functions
 */
85
xf86CrtcPtr
86
xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs)
87
{
88 89
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CrtcPtr crtc, *crtcs;
90

91
    crtc = calloc(sizeof(xf86CrtcRec), 1);
92
    if (!crtc)
93
        return NULL;
94
    crtc->version = XF86_CRTC_VERSION;
95 96 97 98 99 100 101
    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;
102 103 104
    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);
105 106 107 108 109 110
    crtc->filter = NULL;
    crtc->params = NULL;
    crtc->nparams = 0;
    crtc->filter_width = 0;
    crtc->filter_height = 0;
    crtc->transform_in_use = FALSE;
111 112
    crtc->transformPresent = FALSE;
    crtc->desiredTransformPresent = FALSE;
113
    memset(&crtc->bounds, '\0', sizeof(crtc->bounds));
114

115 116
    /* Preallocate gamma at a sensible size. */
    crtc->gamma_size = 256;
117
    crtc->gamma_red = xallocarray(crtc->gamma_size, 3 * sizeof(CARD16));
118
    if (!crtc->gamma_red) {
119 120
        free(crtc);
        return NULL;
121
    }
122 123 124
    crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
    crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;

125
    if (xf86_config->crtc)
126 127
        crtcs = reallocarray(xf86_config->crtc,
                             xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
128
    else
129
        crtcs = xallocarray(xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
130 131 132 133
    if (!crtcs) {
        free(crtc->gamma_red);
        free(crtc);
        return NULL;
134 135 136 137 138 139
    }
    xf86_config->crtc = crtcs;
    xf86_config->crtc[xf86_config->num_crtc++] = crtc;
    return crtc;
}

140
void
141
xf86CrtcDestroy(xf86CrtcPtr crtc)
142
{
143 144 145
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    int c;

146 147
    (*crtc->funcs->destroy) (crtc);
    for (c = 0; c < xf86_config->num_crtc; c++)
148 149 150 151 152 153 154
        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;
        }
155
    free(crtc->params);
156
    free(crtc->gamma_red);
157
    free(crtc);
158 159 160 161 162 163
}

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

164
Bool
165
xf86CrtcInUse(xf86CrtcPtr crtc)
166
{
167 168 169 170
    ScrnInfoPtr pScrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    int o;

171
    for (o = 0; o < xf86_config->num_output; o++)
172 173
        if (xf86_config->output[o]->crtc == crtc)
            return TRUE;
174 175 176
    return FALSE;
}

177
void
178
xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen)
179
{
180 181
    int subpixel_order = SubPixelUnknown;
    Bool has_none = FALSE;
182
    ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
183
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
Keith Packard's avatar
Keith Packard committed
184
    int icrtc, o;
185

Keith Packard's avatar
Keith Packard committed
186 187
    for (icrtc = 0; icrtc < xf86_config->num_crtc; icrtc++) {
        xf86CrtcPtr crtc = xf86_config->crtc[icrtc];
188 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

        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;
Keith Packard's avatar
Keith Packard committed
215
            int sc;
216 217 218 219

            for (rotate = 0; rotate < 4; rotate++)
                if (crtc->rotation & (1 << rotate))
                    break;
Keith Packard's avatar
Keith Packard committed
220 221
            for (sc = 0; sc < 4; sc++)
                if (circle[sc] == subpixel_order)
222
                    break;
Keith Packard's avatar
Keith Packard committed
223 224 225 226 227 228
            sc = (sc + rotate) & 0x3;
            if ((crtc->rotation & RR_Reflect_X) && !(sc & 1))
                sc ^= 2;
            if ((crtc->rotation & RR_Reflect_Y) && (sc & 1))
                sc ^= 2;
            subpixel_order = circle[sc];
229 230
            break;
        }
231 232
    }
    if (subpixel_order == SubPixelUnknown && has_none)
233 234
        subpixel_order = SubPixelNone;
    PictureSetSubpixelOrder(pScreen, subpixel_order);
235 236
}

237 238 239
/**
 * Sets the given video mode on the given crtc
 */
240
Bool
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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);
258

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

266 267
    adjusted_mode = xf86DuplicateMode(mode);

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

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

292
    if (crtc->funcs->set_mode_major) {
293 294
        ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y);
        goto done;
295 296
    }

297
    didLock = crtc->funcs->lock(crtc);
298 299 300 301 302
    /* 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++) {
303
        xf86OutputPtr output = xf86_config->output[i];
304

305 306
        if (output->crtc != crtc)
            continue;
307

308 309 310
        if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
            goto done;
        }
311 312
    }

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

317 318
    if (!xf86CrtcRotate(crtc))
        goto done;
319

Dave Airlie's avatar
Dave Airlie committed
320
    /* Prepare the outputs and CRTCs before setting the mode. */
321
    for (i = 0; i < xf86_config->num_output; i++) {
322
        xf86OutputPtr output = xf86_config->output[i];
323

324 325
        if (output->crtc != crtc)
            continue;
326

327 328
        /* Disable the output as the first thing we do. */
        output->funcs->prepare(output);
329 330
    }

Dave Airlie's avatar
Dave Airlie committed
331
    crtc->funcs->prepare(crtc);
332 333 334 335

    /* Set up the DPLL and any output state that needs to adjust or depend
     * on the DPLL.
     */
336
    crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y);
337 338 339 340 341
    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);
342 343
    }

344
    /* Only upload when needed, to avoid unneeded delays. */
345
    if (!crtc->active && crtc->funcs->gamma_set)
346 347
        crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
                               crtc->gamma_blue, crtc->gamma_size);
348

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

        if (output->crtc == crtc)
            output->funcs->commit(output);
356 357 358
    }

    ret = TRUE;
359

360
 done:
361
    if (ret) {
362 363 364 365 366
        crtc->active = TRUE;
        if (scrn->pScreen)
            xf86CrtcSetScreenSubpixelOrder(scrn->pScreen);
        if (scrn->ModeSet)
            scrn->ModeSet(scrn);
367 368 369 370 371 372

        /* Make sure the HW cursor is hidden if it's supposed to be, in case
         * it was hidden while the CRTC was disabled
         */
        if (!xf86_config->cursor_on)
            xf86_hide_cursors(scrn);
373 374 375 376 377 378 379 380 381
    }
    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;
382 383
    }

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

387
    if (didLock)
388
        crtc->funcs->unlock(crtc);
389 390 391 392

    return ret;
}

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

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

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

425 426 427 428 429 430 431 432
/*
 * Output functions
 */

extern XF86ConfigPtr xf86configptr;

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

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

470 471 472 473 474
enum {
    OPTION_MODEDEBUG,
};

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

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

    if (!output->name)
486
        return;
487

488
    free(output->options);
489

490 491
    output->options = xnfalloc(sizeof(xf86OutputOptions));
    memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions));
492 493

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

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

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

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

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

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

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

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

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

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

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

    if (name)
595
        len = strlen(name) + 1;
596
    else
597
        len = 0;
598

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

624
    if (xf86_config->output)
625 626 627
        outputs = reallocarray(xf86_config->output,
                               xf86_config->num_output + 1,
                               sizeof(xf86OutputPtr));
628
    else
629 630
        outputs = xallocarray(xf86_config->num_output + 1,
                              sizeof(xf86OutputPtr));
631 632 633
    if (!outputs) {
        free(output);
        return NULL;
634
    }
635

636
    xf86_config->output = outputs;
637

638 639 640 641
    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;
642
    }
643 644
    else {
        xf86_config->output[xf86_config->num_output] = output;
645 646 647 648
    }

    xf86_config->num_output++;

649 650 651
    return output;
}

652
Bool
653
xf86OutputRename(xf86OutputPtr output, const char *name)
654
{
655 656
    char *newname = strdup(name);

657
    if (!newname)
658 659
        return FALSE;           /* so sorry... */

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

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

678
void
679
xf86OutputDestroy(xf86OutputPtr output)
680
{
681 682 683 684
    ScrnInfoPtr scrn = output->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int o;

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

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

    screen->CreateScreenResources = config->CreateScreenResources;

712 713 714 715 716
    if (!(*screen->CreateScreenResources) (screen))
        return FALSE;

    if (!xf86RandR12CreateScreenResources(screen))
        return FALSE;
717 718 719 720

    return TRUE;
}

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

731 732
    screen->CloseScreen = config->CloseScreen;

733
    xf86RotateCloseScreen(screen);
734

735 736 737 738
    xf86RandR12CloseScreen(screen);

    screen->CloseScreen(screen);

739 740
    for (o = 0; o < config->num_output; o++) {
        xf86OutputPtr output = config->output[o];
741

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

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

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

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

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

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

795 796 797
    /* Wrap CreateScreenResources so we can initialize the RandR code */
    config->CreateScreenResources = screen->CreateScreenResources;
    screen->CreateScreenResources = xf86CrtcCreateScreenResources;
798 799 800

    config->CloseScreen = screen->CloseScreen;
    screen->CloseScreen = xf86CrtcCloseScreen;
801 802 803

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

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

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

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

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

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

894
static DisplayModePtr
895
xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height)
896
{
897
    DisplayModePtr mode;
898

899 900 901 902
    for (mode = output->probed_modes; mode; mode = mode->next) {
        if (xf86ModeWidth(mode, output->initial_rotation) > width ||
            xf86ModeHeight(mode, output->initial_rotation) > height)
            continue;
903

904 905
        if (mode->type & M_T_PREFERRED)
            return mode;
906
    }
907 908 909 910
    return NULL;
}

static DisplayModePtr
911
xf86OutputHasUserPreferredMode(xf86OutputPtr output)
912 913 914 915
{
    DisplayModePtr mode, first = output->probed_modes;

    for (mode = first; mode && mode->next != first; mode = mode->next)
916 917
        if (mode->type & M_T_USERPREF)
            return mode;
918 919

    return NULL;
920 921 922
}

static int
923 924 925 926 927 928 929 930 931 932 933 934 935
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;

936
    if (n == config->num_output)
937
        return 0;
938
    output = config->output[n];
939

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

948
    crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr));
949
    if (!crtcs)
950
        return best_score;
951 952 953 954

    my_score = 1;
    /* Score outputs that are known to be connected higher */
    if (output->status == XF86OutputStatusConnected)
955
        my_score++;
956
    /* Score outputs with preferred modes higher */
957 958
    if (xf86OutputHasPreferredMode(output, width, height))
        my_score++;