rrcrtc.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2006 Keith Packard
335c4bbdfSmrg * Copyright 2010 Red Hat, Inc
405b261ecSmrg *
505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
705b261ecSmrg * the above copyright notice appear in all copies and that both that copyright
805b261ecSmrg * notice and this permission notice appear in supporting documentation, and
905b261ecSmrg * that the name of the copyright holders not be used in advertising or
1005b261ecSmrg * publicity pertaining to distribution of the software without specific,
1105b261ecSmrg * written prior permission.  The copyright holders make no representations
1205b261ecSmrg * about the suitability of this software for any purpose.  It is provided "as
1305b261ecSmrg * is" without express or implied warranty.
1405b261ecSmrg *
1505b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1705b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2105b261ecSmrg * OF THIS SOFTWARE.
2205b261ecSmrg */
2305b261ecSmrg
2405b261ecSmrg#include "randrstr.h"
2505b261ecSmrg#include "swaprep.h"
2635c4bbdfSmrg#include "mipointer.h"
2705b261ecSmrg
2835c4bbdfSmrgRESTYPE RRCrtcType;
2905b261ecSmrg
3005b261ecSmrg/*
3105b261ecSmrg * Notify the CRTC of some change
3205b261ecSmrg */
3305b261ecSmrgvoid
3435c4bbdfSmrgRRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged)
3505b261ecSmrg{
3635c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
3705b261ecSmrg
3805b261ecSmrg    crtc->changed = TRUE;
3935c4bbdfSmrg    if (pScreen) {
4035c4bbdfSmrg        rrScrPriv(pScreen);
4135c4bbdfSmrg
4235c4bbdfSmrg        RRSetChanged(pScreen);
4335c4bbdfSmrg        /*
4435c4bbdfSmrg         * Send ConfigureNotify on any layout change
4535c4bbdfSmrg         */
4635c4bbdfSmrg        if (layoutChanged)
4735c4bbdfSmrg            pScrPriv->layoutChanged = TRUE;
4805b261ecSmrg    }
4905b261ecSmrg}
5005b261ecSmrg
5105b261ecSmrg/*
5205b261ecSmrg * Create a CRTC
5305b261ecSmrg */
5405b261ecSmrgRRCrtcPtr
5535c4bbdfSmrgRRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
5605b261ecSmrg{
5735c4bbdfSmrg    RRCrtcPtr crtc;
5835c4bbdfSmrg    RRCrtcPtr *crtcs;
5935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
6005b261ecSmrg
6105b261ecSmrg    if (!RRInit())
6235c4bbdfSmrg        return NULL;
6335c4bbdfSmrg
6405b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
6505b261ecSmrg
6605b261ecSmrg    /* make space for the crtc pointer */
6705b261ecSmrg    if (pScrPriv->numCrtcs)
6835c4bbdfSmrg        crtcs = reallocarray(pScrPriv->crtcs,
6935c4bbdfSmrg                             pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr));
7005b261ecSmrg    else
7135c4bbdfSmrg        crtcs = malloc(sizeof(RRCrtcPtr));
7205b261ecSmrg    if (!crtcs)
7335c4bbdfSmrg        return FALSE;
7405b261ecSmrg    pScrPriv->crtcs = crtcs;
7535c4bbdfSmrg
7635c4bbdfSmrg    crtc = calloc(1, sizeof(RRCrtcRec));
7705b261ecSmrg    if (!crtc)
7835c4bbdfSmrg        return NULL;
7935c4bbdfSmrg    crtc->id = FakeClientID(0);
8005b261ecSmrg    crtc->pScreen = pScreen;
8105b261ecSmrg    crtc->mode = NULL;
8205b261ecSmrg    crtc->x = 0;
8305b261ecSmrg    crtc->y = 0;
8405b261ecSmrg    crtc->rotation = RR_Rotate_0;
8505b261ecSmrg    crtc->rotations = RR_Rotate_0;
8605b261ecSmrg    crtc->outputs = NULL;
8705b261ecSmrg    crtc->numOutputs = 0;
8805b261ecSmrg    crtc->gammaSize = 0;
8905b261ecSmrg    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
9005b261ecSmrg    crtc->changed = FALSE;
9105b261ecSmrg    crtc->devPrivate = devPrivate;
9235c4bbdfSmrg    RRTransformInit(&crtc->client_pending_transform);
9335c4bbdfSmrg    RRTransformInit(&crtc->client_current_transform);
9435c4bbdfSmrg    pixman_transform_init_identity(&crtc->transform);
9535c4bbdfSmrg    pixman_f_transform_init_identity(&crtc->f_transform);
9635c4bbdfSmrg    pixman_f_transform_init_identity(&crtc->f_inverse);
9705b261ecSmrg
9835c4bbdfSmrg    if (!AddResource(crtc->id, RRCrtcType, (void *) crtc))
9935c4bbdfSmrg        return NULL;
10005b261ecSmrg
10105b261ecSmrg    /* attach the screen and crtc together */
10205b261ecSmrg    crtc->pScreen = pScreen;
10305b261ecSmrg    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
10435c4bbdfSmrg
10535c4bbdfSmrg    RRResourcesChanged(pScreen);
10635c4bbdfSmrg
10705b261ecSmrg    return crtc;
10805b261ecSmrg}
10905b261ecSmrg
11005b261ecSmrg/*
11105b261ecSmrg * Set the allowed rotations on a CRTC
11205b261ecSmrg */
11305b261ecSmrgvoid
11435c4bbdfSmrgRRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations)
11505b261ecSmrg{
11605b261ecSmrg    crtc->rotations = rotations;
11705b261ecSmrg}
11805b261ecSmrg
1194642e01fSmrg/*
1204642e01fSmrg * Set whether transforms are allowed on a CRTC
1214642e01fSmrg */
1224642e01fSmrgvoid
12335c4bbdfSmrgRRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
1244642e01fSmrg{
1254642e01fSmrg    crtc->transforms = transforms;
1264642e01fSmrg}
1274642e01fSmrg
12805b261ecSmrg/*
12905b261ecSmrg * Notify the extension that the Crtc has been reconfigured,
13005b261ecSmrg * the driver calls this whenever it has updated the mode
13105b261ecSmrg */
13205b261ecSmrgBool
13335c4bbdfSmrgRRCrtcNotify(RRCrtcPtr crtc,
13435c4bbdfSmrg             RRModePtr mode,
13535c4bbdfSmrg             int x,
13635c4bbdfSmrg             int y,
13735c4bbdfSmrg             Rotation rotation,
13835c4bbdfSmrg             RRTransformPtr transform, int numOutputs, RROutputPtr * outputs)
13905b261ecSmrg{
14035c4bbdfSmrg    int i, j;
14135c4bbdfSmrg
14205b261ecSmrg    /*
14305b261ecSmrg     * Check to see if any of the new outputs were
14405b261ecSmrg     * not in the old list and mark them as changed
14505b261ecSmrg     */
14635c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
14735c4bbdfSmrg        for (j = 0; j < crtc->numOutputs; j++)
14835c4bbdfSmrg            if (outputs[i] == crtc->outputs[j])
14935c4bbdfSmrg                break;
15035c4bbdfSmrg        if (j == crtc->numOutputs) {
15135c4bbdfSmrg            outputs[i]->crtc = crtc;
15235c4bbdfSmrg            RROutputChanged(outputs[i], FALSE);
15335c4bbdfSmrg            RRCrtcChanged(crtc, FALSE);
15435c4bbdfSmrg        }
15505b261ecSmrg    }
15605b261ecSmrg    /*
15705b261ecSmrg     * Check to see if any of the old outputs are
15805b261ecSmrg     * not in the new list and mark them as changed
15905b261ecSmrg     */
16035c4bbdfSmrg    for (j = 0; j < crtc->numOutputs; j++) {
16135c4bbdfSmrg        for (i = 0; i < numOutputs; i++)
16235c4bbdfSmrg            if (outputs[i] == crtc->outputs[j])
16335c4bbdfSmrg                break;
16435c4bbdfSmrg        if (i == numOutputs) {
16535c4bbdfSmrg            if (crtc->outputs[j]->crtc == crtc)
16635c4bbdfSmrg                crtc->outputs[j]->crtc = NULL;
16735c4bbdfSmrg            RROutputChanged(crtc->outputs[j], FALSE);
16835c4bbdfSmrg            RRCrtcChanged(crtc, FALSE);
16935c4bbdfSmrg        }
17005b261ecSmrg    }
17105b261ecSmrg    /*
17205b261ecSmrg     * Reallocate the crtc output array if necessary
17305b261ecSmrg     */
17435c4bbdfSmrg    if (numOutputs != crtc->numOutputs) {
17535c4bbdfSmrg        RROutputPtr *newoutputs;
17635c4bbdfSmrg
17735c4bbdfSmrg        if (numOutputs) {
17835c4bbdfSmrg            if (crtc->numOutputs)
17935c4bbdfSmrg                newoutputs = reallocarray(crtc->outputs,
18035c4bbdfSmrg                                          numOutputs, sizeof(RROutputPtr));
18135c4bbdfSmrg            else
18235c4bbdfSmrg                newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr));
18335c4bbdfSmrg            if (!newoutputs)
18435c4bbdfSmrg                return FALSE;
18535c4bbdfSmrg        }
18635c4bbdfSmrg        else {
18735c4bbdfSmrg            free(crtc->outputs);
18835c4bbdfSmrg            newoutputs = NULL;
18935c4bbdfSmrg        }
19035c4bbdfSmrg        crtc->outputs = newoutputs;
19135c4bbdfSmrg        crtc->numOutputs = numOutputs;
19205b261ecSmrg    }
19305b261ecSmrg    /*
19405b261ecSmrg     * Copy the new list of outputs into the crtc
19505b261ecSmrg     */
19635c4bbdfSmrg    memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr));
19705b261ecSmrg    /*
19805b261ecSmrg     * Update remaining crtc fields
19905b261ecSmrg     */
20035c4bbdfSmrg    if (mode != crtc->mode) {
20135c4bbdfSmrg        if (crtc->mode)
20235c4bbdfSmrg            RRModeDestroy(crtc->mode);
20335c4bbdfSmrg        crtc->mode = mode;
20435c4bbdfSmrg        if (mode != NULL)
20535c4bbdfSmrg            mode->refcnt++;
20635c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
20705b261ecSmrg    }
20835c4bbdfSmrg    if (x != crtc->x) {
20935c4bbdfSmrg        crtc->x = x;
21035c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
21105b261ecSmrg    }
21235c4bbdfSmrg    if (y != crtc->y) {
21335c4bbdfSmrg        crtc->y = y;
21435c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
21505b261ecSmrg    }
21635c4bbdfSmrg    if (rotation != crtc->rotation) {
21735c4bbdfSmrg        crtc->rotation = rotation;
21835c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
2194642e01fSmrg    }
22035c4bbdfSmrg    if (!RRTransformEqual(transform, &crtc->client_current_transform)) {
22135c4bbdfSmrg        RRTransformCopy(&crtc->client_current_transform, transform);
22235c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
22335c4bbdfSmrg    }
22435c4bbdfSmrg    if (crtc->changed && mode) {
22535c4bbdfSmrg        RRTransformCompute(x, y,
22635c4bbdfSmrg                           mode->mode.width, mode->mode.height,
22735c4bbdfSmrg                           rotation,
22835c4bbdfSmrg                           &crtc->client_current_transform,
22935c4bbdfSmrg                           &crtc->transform, &crtc->f_transform,
23035c4bbdfSmrg                           &crtc->f_inverse);
2314642e01fSmrg    }
23205b261ecSmrg    return TRUE;
23305b261ecSmrg}
23405b261ecSmrg
23505b261ecSmrgvoid
23635c4bbdfSmrgRRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
23705b261ecSmrg{
23805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
23935c4bbdfSmrg
24035c4bbdfSmrg    rrScrPriv(pScreen);
24135c4bbdfSmrg    RRModePtr mode = crtc->mode;
24235c4bbdfSmrg
24335c4bbdfSmrg    xRRCrtcChangeNotifyEvent ce = {
24435c4bbdfSmrg        .type = RRNotify + RREventBase,
24535c4bbdfSmrg        .subCode = RRNotify_CrtcChange,
24635c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
24735c4bbdfSmrg        .window = pWin->drawable.id,
24835c4bbdfSmrg        .crtc = crtc->id,
24935c4bbdfSmrg        .mode = mode ? mode->mode.id : None,
25035c4bbdfSmrg        .rotation = crtc->rotation,
25135c4bbdfSmrg        .x = mode ? crtc->x : 0,
25235c4bbdfSmrg        .y = mode ? crtc->y : 0,
25335c4bbdfSmrg        .width = mode ? mode->mode.width : 0,
25435c4bbdfSmrg        .height = mode ? mode->mode.height : 0
25535c4bbdfSmrg    };
25635c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &ce);
25735c4bbdfSmrg}
25835c4bbdfSmrg
25935c4bbdfSmrgstatic Bool
26035c4bbdfSmrgRRCrtcPendingProperties(RRCrtcPtr crtc)
26135c4bbdfSmrg{
26235c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
26335c4bbdfSmrg
26435c4bbdfSmrg    rrScrPriv(pScreen);
26535c4bbdfSmrg    int o;
26635c4bbdfSmrg
26735c4bbdfSmrg    for (o = 0; o < pScrPriv->numOutputs; o++) {
26835c4bbdfSmrg        RROutputPtr output = pScrPriv->outputs[o];
26935c4bbdfSmrg
27035c4bbdfSmrg        if (output->crtc == crtc && output->pendingProperties)
27135c4bbdfSmrg            return TRUE;
27205b261ecSmrg    }
27335c4bbdfSmrg    return FALSE;
27435c4bbdfSmrg}
27535c4bbdfSmrg
27635c4bbdfSmrgstatic void
27735c4bbdfSmrgcrtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
27835c4bbdfSmrg{
27935c4bbdfSmrg    *left = crtc->x;
28035c4bbdfSmrg    *top = crtc->y;
28135c4bbdfSmrg
28235c4bbdfSmrg    switch (crtc->rotation) {
28335c4bbdfSmrg    case RR_Rotate_0:
28435c4bbdfSmrg    case RR_Rotate_180:
28535c4bbdfSmrg    default:
28635c4bbdfSmrg        *right = crtc->x + crtc->mode->mode.width;
28735c4bbdfSmrg        *bottom = crtc->y + crtc->mode->mode.height;
28835c4bbdfSmrg        return;
28935c4bbdfSmrg    case RR_Rotate_90:
29035c4bbdfSmrg    case RR_Rotate_270:
29135c4bbdfSmrg        *right = crtc->x + crtc->mode->mode.height;
29235c4bbdfSmrg        *bottom = crtc->y + crtc->mode->mode.width;
29335c4bbdfSmrg        return;
29405b261ecSmrg    }
29505b261ecSmrg}
29605b261ecSmrg
29735c4bbdfSmrg/* overlapping counts as adjacent */
29805b261ecSmrgstatic Bool
29935c4bbdfSmrgcrtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
30035c4bbdfSmrg{
30135c4bbdfSmrg    /* left, right, top, bottom... */
30235c4bbdfSmrg    int al, ar, at, ab;
30335c4bbdfSmrg    int bl, br, bt, bb;
30435c4bbdfSmrg    int cl, cr, ct, cb;         /* the overlap, if any */
30535c4bbdfSmrg
30635c4bbdfSmrg    crtc_bounds(a, &al, &ar, &at, &ab);
30735c4bbdfSmrg    crtc_bounds(b, &bl, &br, &bt, &bb);
30835c4bbdfSmrg
30935c4bbdfSmrg    cl = max(al, bl);
31035c4bbdfSmrg    cr = min(ar, br);
31135c4bbdfSmrg    ct = max(at, bt);
31235c4bbdfSmrg    cb = min(ab, bb);
31335c4bbdfSmrg
31435c4bbdfSmrg    return (cl <= cr) && (ct <= cb);
31535c4bbdfSmrg}
31635c4bbdfSmrg
31735c4bbdfSmrg/* Depth-first search and mark all CRTCs reachable from cur */
31835c4bbdfSmrgstatic void
31935c4bbdfSmrgmark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur)
32035c4bbdfSmrg{
32135c4bbdfSmrg    int i;
32235c4bbdfSmrg
32335c4bbdfSmrg    reachable[cur] = TRUE;
32435c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; ++i) {
32535c4bbdfSmrg        if (reachable[i] || !pScrPriv->crtcs[i]->mode)
32635c4bbdfSmrg            continue;
32735c4bbdfSmrg        if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
32835c4bbdfSmrg            mark_crtcs(pScrPriv, reachable, i);
32935c4bbdfSmrg    }
33035c4bbdfSmrg}
33135c4bbdfSmrg
33235c4bbdfSmrgstatic void
33335c4bbdfSmrgRRComputeContiguity(ScreenPtr pScreen)
33405b261ecSmrg{
33505b261ecSmrg    rrScrPriv(pScreen);
33635c4bbdfSmrg    Bool discontiguous = TRUE;
33735c4bbdfSmrg    int i, n = pScrPriv->numCrtcs;
33805b261ecSmrg
33935c4bbdfSmrg    int *reachable = calloc(n, sizeof(int));
34035c4bbdfSmrg
34135c4bbdfSmrg    if (!reachable)
34235c4bbdfSmrg        goto out;
34335c4bbdfSmrg
34435c4bbdfSmrg    /* Find first enabled CRTC and start search for reachable CRTCs from it */
34535c4bbdfSmrg    for (i = 0; i < n; ++i) {
34635c4bbdfSmrg        if (pScrPriv->crtcs[i]->mode) {
34735c4bbdfSmrg            mark_crtcs(pScrPriv, reachable, i);
34835c4bbdfSmrg            break;
34935c4bbdfSmrg        }
35005b261ecSmrg    }
35135c4bbdfSmrg
35235c4bbdfSmrg    /* Check that all enabled CRTCs were marked as reachable */
35335c4bbdfSmrg    for (i = 0; i < n; ++i)
35435c4bbdfSmrg        if (pScrPriv->crtcs[i]->mode && !reachable[i])
35535c4bbdfSmrg            goto out;
35635c4bbdfSmrg
35735c4bbdfSmrg    discontiguous = FALSE;
35835c4bbdfSmrg
35935c4bbdfSmrg out:
36035c4bbdfSmrg    free(reachable);
36135c4bbdfSmrg    pScrPriv->discontiguous = discontiguous;
36235c4bbdfSmrg}
36335c4bbdfSmrg
36435c4bbdfSmrgvoid
36535c4bbdfSmrgRRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
36635c4bbdfSmrg{
36735c4bbdfSmrg    ScreenPtr master = crtc->pScreen->current_master;
36835c4bbdfSmrg    PixmapPtr mscreenpix;
36935c4bbdfSmrg    rrScrPriv(crtc->pScreen);
37035c4bbdfSmrg
37135c4bbdfSmrg    mscreenpix = master->GetScreenPixmap(master);
37235c4bbdfSmrg
37335c4bbdfSmrg    pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
37435c4bbdfSmrg    if (crtc->scanout_pixmap) {
37535c4bbdfSmrg        master->StopPixmapTracking(mscreenpix, crtc->scanout_pixmap);
37635c4bbdfSmrg        /*
37735c4bbdfSmrg         * Unref the pixmap twice: once for the original reference, and once
37835c4bbdfSmrg         * for the reference implicitly added by PixmapShareToSlave.
37935c4bbdfSmrg         */
38035c4bbdfSmrg        master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap);
38135c4bbdfSmrg        master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap);
38235c4bbdfSmrg        crtc->pScreen->DestroyPixmap(crtc->scanout_pixmap);
38335c4bbdfSmrg    }
38435c4bbdfSmrg    crtc->scanout_pixmap = NULL;
38535c4bbdfSmrg    RRCrtcChanged(crtc, TRUE);
38635c4bbdfSmrg}
38735c4bbdfSmrg
38835c4bbdfSmrgstatic Bool
38935c4bbdfSmrgrrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height,
39035c4bbdfSmrg                     int x, int y, Rotation rotation)
39135c4bbdfSmrg{
39235c4bbdfSmrg    PixmapPtr mpix, spix;
39335c4bbdfSmrg    ScreenPtr master = crtc->pScreen->current_master;
39435c4bbdfSmrg    Bool ret;
39535c4bbdfSmrg    int depth;
39635c4bbdfSmrg    PixmapPtr mscreenpix;
39735c4bbdfSmrg    PixmapPtr protopix = master->GetScreenPixmap(master);
39835c4bbdfSmrg    rrScrPriv(crtc->pScreen);
39935c4bbdfSmrg
40035c4bbdfSmrg    /* create a pixmap on the master screen,
40135c4bbdfSmrg       then get a shared handle for it
40235c4bbdfSmrg       create a shared pixmap on the slave screen using the handle
40335c4bbdfSmrg       set the master screen to do dirty updates to the shared pixmap
40435c4bbdfSmrg       from the screen pixmap.
40535c4bbdfSmrg       set slave screen to scanout shared linear pixmap
40635c4bbdfSmrg    */
40735c4bbdfSmrg
40835c4bbdfSmrg    mscreenpix = master->GetScreenPixmap(master);
40935c4bbdfSmrg    depth = protopix->drawable.depth;
41035c4bbdfSmrg
41135c4bbdfSmrg    if (crtc->scanout_pixmap)
41235c4bbdfSmrg        RRCrtcDetachScanoutPixmap(crtc);
41335c4bbdfSmrg
41435c4bbdfSmrg    if (width == 0 && height == 0) {
41535c4bbdfSmrg        return TRUE;
41635c4bbdfSmrg    }
41735c4bbdfSmrg
41835c4bbdfSmrg    mpix = master->CreatePixmap(master, width, height, depth,
41935c4bbdfSmrg                                CREATE_PIXMAP_USAGE_SHARED);
42035c4bbdfSmrg    if (!mpix)
42135c4bbdfSmrg        return FALSE;
42235c4bbdfSmrg
42335c4bbdfSmrg    spix = PixmapShareToSlave(mpix, crtc->pScreen);
42435c4bbdfSmrg    if (spix == NULL) {
42535c4bbdfSmrg        master->DestroyPixmap(mpix);
42635c4bbdfSmrg        return FALSE;
42735c4bbdfSmrg    }
42835c4bbdfSmrg
42935c4bbdfSmrg    ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix);
43035c4bbdfSmrg    if (ret == FALSE) {
43135c4bbdfSmrg        ErrorF("randr: failed to set shadow slave pixmap\n");
43235c4bbdfSmrg        return FALSE;
43335c4bbdfSmrg    }
43435c4bbdfSmrg
43535c4bbdfSmrg    crtc->scanout_pixmap = spix;
43635c4bbdfSmrg
43735c4bbdfSmrg    master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation);
43835c4bbdfSmrg    return TRUE;
43935c4bbdfSmrg}
44035c4bbdfSmrg
44135c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
44235c4bbdfSmrg{
44335c4bbdfSmrg    box->x1 = crtc->x;
44435c4bbdfSmrg    box->y1 = crtc->y;
44535c4bbdfSmrg    switch (crtc->rotation) {
44635c4bbdfSmrg    case RR_Rotate_0:
44735c4bbdfSmrg    case RR_Rotate_180:
44835c4bbdfSmrg    default:
44935c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.width;
45035c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.height;
45135c4bbdfSmrg        break;
45235c4bbdfSmrg    case RR_Rotate_90:
45335c4bbdfSmrg    case RR_Rotate_270:
45435c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.height;
45535c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.width;
45635c4bbdfSmrg        break;
45735c4bbdfSmrg    }
45835c4bbdfSmrg}
45935c4bbdfSmrg
46035c4bbdfSmrgstatic Bool
46135c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen,
46235c4bbdfSmrg                      RRCrtcPtr rr_crtc, Rotation rotation,
46335c4bbdfSmrg                      int x, int y, int w, int h)
46435c4bbdfSmrg{
46535c4bbdfSmrg    RegionRec root_pixmap_region, total_region, new_crtc_region;
46635c4bbdfSmrg    int c;
46735c4bbdfSmrg    BoxRec newbox;
46835c4bbdfSmrg    BoxPtr newsize;
46935c4bbdfSmrg    ScreenPtr slave;
47035c4bbdfSmrg    int new_width, new_height;
47135c4bbdfSmrg    PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
47235c4bbdfSmrg    rrScrPriv(pScreen);
47335c4bbdfSmrg
47435c4bbdfSmrg    PixmapRegionInit(&root_pixmap_region, screen_pixmap);
47535c4bbdfSmrg    RegionInit(&total_region, NULL, 0);
47635c4bbdfSmrg
47735c4bbdfSmrg    /* have to iterate all the crtcs of the attached gpu masters
47835c4bbdfSmrg       and all their output slaves */
47935c4bbdfSmrg    for (c = 0; c < pScrPriv->numCrtcs; c++) {
48035c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[c];
48135c4bbdfSmrg
48235c4bbdfSmrg        if (crtc == rr_crtc) {
48335c4bbdfSmrg            newbox.x1 = x;
48435c4bbdfSmrg            newbox.y1 = y;
48535c4bbdfSmrg            if (rotation == RR_Rotate_90 ||
48635c4bbdfSmrg                rotation == RR_Rotate_270) {
48735c4bbdfSmrg                newbox.x2 = x + h;
48835c4bbdfSmrg                newbox.y2 = y + w;
48935c4bbdfSmrg            } else {
49035c4bbdfSmrg                newbox.x2 = x + w;
49135c4bbdfSmrg                newbox.y2 = y + h;
49235c4bbdfSmrg            }
49335c4bbdfSmrg        } else {
49435c4bbdfSmrg            if (!crtc->mode)
49535c4bbdfSmrg                continue;
49635c4bbdfSmrg            crtc_to_box(&newbox, crtc);
49735c4bbdfSmrg        }
49835c4bbdfSmrg        RegionInit(&new_crtc_region, &newbox, 1);
49935c4bbdfSmrg        RegionUnion(&total_region, &total_region, &new_crtc_region);
50035c4bbdfSmrg    }
50135c4bbdfSmrg
50235c4bbdfSmrg    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
50335c4bbdfSmrg        rrScrPrivPtr    slave_priv = rrGetScrPriv(slave);
50435c4bbdfSmrg        for (c = 0; c < slave_priv->numCrtcs; c++) {
50535c4bbdfSmrg            RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
50635c4bbdfSmrg
50735c4bbdfSmrg            if (slave_crtc == rr_crtc) {
50835c4bbdfSmrg                newbox.x1 = x;
50935c4bbdfSmrg                newbox.y1 = y;
51035c4bbdfSmrg                if (rotation == RR_Rotate_90 ||
51135c4bbdfSmrg                    rotation == RR_Rotate_270) {
51235c4bbdfSmrg                    newbox.x2 = x + h;
51335c4bbdfSmrg                    newbox.y2 = y + w;
51435c4bbdfSmrg                } else {
51535c4bbdfSmrg                    newbox.x2 = x + w;
51635c4bbdfSmrg                    newbox.y2 = y + h;
51735c4bbdfSmrg                }
51835c4bbdfSmrg            }
51935c4bbdfSmrg            else {
52035c4bbdfSmrg                if (!slave_crtc->mode)
52135c4bbdfSmrg                    continue;
52235c4bbdfSmrg                crtc_to_box(&newbox, slave_crtc);
52335c4bbdfSmrg            }
52435c4bbdfSmrg            RegionInit(&new_crtc_region, &newbox, 1);
52535c4bbdfSmrg            RegionUnion(&total_region, &total_region, &new_crtc_region);
52635c4bbdfSmrg        }
52735c4bbdfSmrg    }
52835c4bbdfSmrg
52935c4bbdfSmrg    newsize = RegionExtents(&total_region);
53035c4bbdfSmrg    new_width = newsize->x2 - newsize->x1;
53135c4bbdfSmrg    new_height = newsize->y2 - newsize->y1;
53235c4bbdfSmrg
53335c4bbdfSmrg    if (new_width == screen_pixmap->drawable.width &&
53435c4bbdfSmrg        new_height == screen_pixmap->drawable.height) {
53535c4bbdfSmrg    } else {
53635c4bbdfSmrg        pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
53735c4bbdfSmrg    }
53835c4bbdfSmrg
53935c4bbdfSmrg    /* set shatters TODO */
54035c4bbdfSmrg    return TRUE;
54105b261ecSmrg}
54205b261ecSmrg
54305b261ecSmrg/*
54405b261ecSmrg * Request that the Crtc be reconfigured
54505b261ecSmrg */
54605b261ecSmrgBool
54735c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc,
54835c4bbdfSmrg          RRModePtr mode,
54935c4bbdfSmrg          int x,
55035c4bbdfSmrg          int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
55105b261ecSmrg{
55235c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
55335c4bbdfSmrg    Bool ret = FALSE;
55435c4bbdfSmrg    Bool recompute = TRUE;
55535c4bbdfSmrg    Bool crtcChanged;
55635c4bbdfSmrg    int  o;
55735c4bbdfSmrg
55805b261ecSmrg    rrScrPriv(pScreen);
55905b261ecSmrg
56035c4bbdfSmrg    crtcChanged = FALSE;
56135c4bbdfSmrg    for (o = 0; o < numOutputs; o++) {
56235c4bbdfSmrg        if (outputs[o] && outputs[o]->crtc != crtc) {
56335c4bbdfSmrg            crtcChanged = TRUE;
56435c4bbdfSmrg            break;
56535c4bbdfSmrg        }
56635c4bbdfSmrg    }
56735c4bbdfSmrg
56805b261ecSmrg    /* See if nothing changed */
56905b261ecSmrg    if (crtc->mode == mode &&
57035c4bbdfSmrg        crtc->x == x &&
57135c4bbdfSmrg        crtc->y == y &&
57235c4bbdfSmrg        crtc->rotation == rotation &&
57335c4bbdfSmrg        crtc->numOutputs == numOutputs &&
57435c4bbdfSmrg        !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
57535c4bbdfSmrg        !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
57635c4bbdfSmrg        !crtcChanged) {
57735c4bbdfSmrg        recompute = FALSE;
57835c4bbdfSmrg        ret = TRUE;
57905b261ecSmrg    }
58035c4bbdfSmrg    else {
58135c4bbdfSmrg        if (pScreen->isGPU) {
58235c4bbdfSmrg            ScreenPtr master = pScreen->current_master;
58335c4bbdfSmrg            int width = 0, height = 0;
58435c4bbdfSmrg
58535c4bbdfSmrg            if (mode) {
58635c4bbdfSmrg                width = mode->mode.width;
58735c4bbdfSmrg                height = mode->mode.height;
58835c4bbdfSmrg            }
58935c4bbdfSmrg            ret = rrCheckPixmapBounding(master, crtc,
59035c4bbdfSmrg                                        rotation, x, y, width, height);
59135c4bbdfSmrg            if (!ret)
59235c4bbdfSmrg                return FALSE;
59335c4bbdfSmrg
59435c4bbdfSmrg            if (pScreen->current_master) {
59535c4bbdfSmrg                ret = rrCreateSharedPixmap(crtc, width, height, x, y, rotation);
59635c4bbdfSmrg            }
59735c4bbdfSmrg        }
59805b261ecSmrg#if RANDR_12_INTERFACE
59935c4bbdfSmrg        if (pScrPriv->rrCrtcSet) {
60035c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
60135c4bbdfSmrg                                          rotation, numOutputs, outputs);
60235c4bbdfSmrg        }
60335c4bbdfSmrg        else
60405b261ecSmrg#endif
60535c4bbdfSmrg        {
60605b261ecSmrg#if RANDR_10_INTERFACE
60735c4bbdfSmrg            if (pScrPriv->rrSetConfig) {
60835c4bbdfSmrg                RRScreenSize size;
60935c4bbdfSmrg                RRScreenRate rate;
61035c4bbdfSmrg
61135c4bbdfSmrg                if (!mode) {
61235c4bbdfSmrg                    RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
61335c4bbdfSmrg                    ret = TRUE;
61435c4bbdfSmrg                }
61535c4bbdfSmrg                else {
61635c4bbdfSmrg                    size.width = mode->mode.width;
61735c4bbdfSmrg                    size.height = mode->mode.height;
61835c4bbdfSmrg                    if (outputs[0]->mmWidth && outputs[0]->mmHeight) {
61935c4bbdfSmrg                        size.mmWidth = outputs[0]->mmWidth;
62035c4bbdfSmrg                        size.mmHeight = outputs[0]->mmHeight;
62135c4bbdfSmrg                    }
62235c4bbdfSmrg                    else {
62335c4bbdfSmrg                        size.mmWidth = pScreen->mmWidth;
62435c4bbdfSmrg                        size.mmHeight = pScreen->mmHeight;
62535c4bbdfSmrg                    }
62635c4bbdfSmrg                    size.nRates = 1;
62735c4bbdfSmrg                    rate.rate = RRVerticalRefresh(&mode->mode);
62835c4bbdfSmrg                    size.pRates = &rate;
62935c4bbdfSmrg                    ret =
63035c4bbdfSmrg                        (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate,
63135c4bbdfSmrg                                                  &size);
63235c4bbdfSmrg                    /*
63335c4bbdfSmrg                     * Old 1.0 interface tied screen size to mode size
63435c4bbdfSmrg                     */
63535c4bbdfSmrg                    if (ret) {
63635c4bbdfSmrg                        RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
63735c4bbdfSmrg                                     outputs);
63835c4bbdfSmrg                        RRScreenSizeNotify(pScreen);
63935c4bbdfSmrg                    }
64035c4bbdfSmrg                }
64135c4bbdfSmrg            }
64205b261ecSmrg#endif
64335c4bbdfSmrg        }
64435c4bbdfSmrg        if (ret) {
64505b261ecSmrg
64635c4bbdfSmrg            RRTellChanged(pScreen);
64735c4bbdfSmrg
64835c4bbdfSmrg            for (o = 0; o < numOutputs; o++)
64935c4bbdfSmrg                RRPostPendingProperties(outputs[o]);
65035c4bbdfSmrg        }
65105b261ecSmrg    }
65235c4bbdfSmrg
65335c4bbdfSmrg    if (recompute)
65435c4bbdfSmrg        RRComputeContiguity(pScreen);
65535c4bbdfSmrg
65605b261ecSmrg    return ret;
65705b261ecSmrg}
65805b261ecSmrg
6594642e01fSmrg/*
6604642e01fSmrg * Return crtc transform
6614642e01fSmrg */
6624642e01fSmrgRRTransformPtr
66335c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc)
6644642e01fSmrg{
66535c4bbdfSmrg    RRTransformPtr transform = &crtc->client_pending_transform;
6664642e01fSmrg
66735c4bbdfSmrg    if (pixman_transform_is_identity(&transform->transform))
66835c4bbdfSmrg        return NULL;
6694642e01fSmrg    return transform;
6704642e01fSmrg}
6714642e01fSmrg
6724642e01fSmrg/*
6734642e01fSmrg * Check whether the pending and current transforms are the same
6744642e01fSmrg */
6754642e01fSmrgBool
67635c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc)
6774642e01fSmrg{
67835c4bbdfSmrg    return memcmp(&crtc->client_current_transform.transform,
67935c4bbdfSmrg                  &crtc->client_pending_transform.transform,
68035c4bbdfSmrg                  sizeof(PictTransform)) != 0;
6814642e01fSmrg}
6824642e01fSmrg
68305b261ecSmrg/*
68405b261ecSmrg * Destroy a Crtc at shutdown
68505b261ecSmrg */
68605b261ecSmrgvoid
68735c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc)
68805b261ecSmrg{
68935c4bbdfSmrg    FreeResource(crtc->id, 0);
69005b261ecSmrg}
69105b261ecSmrg
69205b261ecSmrgstatic int
69335c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid)
69405b261ecSmrg{
69535c4bbdfSmrg    RRCrtcPtr crtc = (RRCrtcPtr) value;
69635c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
69705b261ecSmrg
69835c4bbdfSmrg    if (pScreen) {
69935c4bbdfSmrg        rrScrPriv(pScreen);
70035c4bbdfSmrg        int i;
70135c4bbdfSmrg
70235c4bbdfSmrg        for (i = 0; i < pScrPriv->numCrtcs; i++) {
70335c4bbdfSmrg            if (pScrPriv->crtcs[i] == crtc) {
70435c4bbdfSmrg                memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
70535c4bbdfSmrg                        (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr));
70635c4bbdfSmrg                --pScrPriv->numCrtcs;
70735c4bbdfSmrg                break;
70835c4bbdfSmrg            }
70935c4bbdfSmrg        }
71035c4bbdfSmrg
71135c4bbdfSmrg        RRResourcesChanged(pScreen);
71205b261ecSmrg    }
71335c4bbdfSmrg
71435c4bbdfSmrg    if (crtc->scanout_pixmap)
71535c4bbdfSmrg        RRCrtcDetachScanoutPixmap(crtc);
7166747b715Smrg    free(crtc->gammaRed);
71705b261ecSmrg    if (crtc->mode)
71835c4bbdfSmrg        RRModeDestroy(crtc->mode);
7196747b715Smrg    free(crtc);
72005b261ecSmrg    return 1;
72105b261ecSmrg}
72205b261ecSmrg
72305b261ecSmrg/*
72405b261ecSmrg * Request that the Crtc gamma be changed
72505b261ecSmrg */
72605b261ecSmrg
72705b261ecSmrgBool
72835c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
72905b261ecSmrg{
73035c4bbdfSmrg    Bool ret = TRUE;
73135c4bbdfSmrg
73205b261ecSmrg#if RANDR_12_INTERFACE
73335c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
73405b261ecSmrg#endif
73535c4bbdfSmrg
73635c4bbdfSmrg    memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16));
73735c4bbdfSmrg    memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16));
73835c4bbdfSmrg    memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16));
73905b261ecSmrg#if RANDR_12_INTERFACE
74035c4bbdfSmrg    if (pScreen) {
74135c4bbdfSmrg        rrScrPriv(pScreen);
74235c4bbdfSmrg        if (pScrPriv->rrCrtcSetGamma)
74335c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
74405b261ecSmrg    }
74505b261ecSmrg#endif
74605b261ecSmrg    return ret;
74705b261ecSmrg}
74805b261ecSmrg
7496747b715Smrg/*
7506747b715Smrg * Request current gamma back from the DDX (if possible).
7516747b715Smrg * This includes gamma size.
7526747b715Smrg */
7536747b715SmrgBool
7546747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc)
7556747b715Smrg{
7566747b715Smrg    Bool ret = TRUE;
75735c4bbdfSmrg
7586747b715Smrg#if RANDR_12_INTERFACE
75935c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
7606747b715Smrg#endif
7616747b715Smrg
7626747b715Smrg#if RANDR_12_INTERFACE
76335c4bbdfSmrg    if (pScreen) {
7646747b715Smrg        rrScrPriv(pScreen);
7656747b715Smrg        if (pScrPriv->rrCrtcGetGamma)
7666747b715Smrg            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
7676747b715Smrg    }
7686747b715Smrg#endif
7696747b715Smrg    return ret;
7706747b715Smrg}
7716747b715Smrg
77205b261ecSmrg/*
77305b261ecSmrg * Notify the extension that the Crtc gamma has been changed
77405b261ecSmrg * The driver calls this whenever it has changed the gamma values
77505b261ecSmrg * in the RRCrtcRec
77605b261ecSmrg */
77705b261ecSmrg
77805b261ecSmrgBool
77935c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc)
78005b261ecSmrg{
78135c4bbdfSmrg    return TRUE;                /* not much going on here */
78205b261ecSmrg}
78305b261ecSmrg
7844642e01fSmrgstatic void
78535c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
78635c4bbdfSmrg                     int *width, int *height)
78705b261ecSmrg{
78835c4bbdfSmrg    BoxRec box;
7894642e01fSmrg
7904642e01fSmrg    if (mode == NULL) {
79135c4bbdfSmrg        *width = 0;
79235c4bbdfSmrg        *height = 0;
79335c4bbdfSmrg        return;
79405b261ecSmrg    }
79505b261ecSmrg
7964642e01fSmrg    box.x1 = 0;
7974642e01fSmrg    box.y1 = 0;
7984642e01fSmrg    box.x2 = mode->mode.width;
7994642e01fSmrg    box.y2 = mode->mode.height;
8004642e01fSmrg
80135c4bbdfSmrg    pixman_transform_bounds(transform, &box);
8024642e01fSmrg    *width = box.x2 - box.x1;
8034642e01fSmrg    *height = box.y2 - box.y1;
8044642e01fSmrg}
8054642e01fSmrg
8064642e01fSmrg/**
8074642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer
8084642e01fSmrg */
8094642e01fSmrgvoid
8104642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
8114642e01fSmrg{
81235c4bbdfSmrg    RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
81305b261ecSmrg}
81405b261ecSmrg
81505b261ecSmrg/*
81605b261ecSmrg * Set the size of the gamma table at server startup time
81705b261ecSmrg */
81805b261ecSmrg
81905b261ecSmrgBool
82035c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
82105b261ecSmrg{
82235c4bbdfSmrg    CARD16 *gamma;
82305b261ecSmrg
82405b261ecSmrg    if (size == crtc->gammaSize)
82535c4bbdfSmrg        return TRUE;
82635c4bbdfSmrg    if (size) {
82735c4bbdfSmrg        gamma = xallocarray(size, 3 * sizeof(CARD16));
82835c4bbdfSmrg        if (!gamma)
82935c4bbdfSmrg            return FALSE;
83005b261ecSmrg    }
83105b261ecSmrg    else
83235c4bbdfSmrg        gamma = NULL;
8336747b715Smrg    free(crtc->gammaRed);
83405b261ecSmrg    crtc->gammaRed = gamma;
83505b261ecSmrg    crtc->gammaGreen = gamma + size;
83635c4bbdfSmrg    crtc->gammaBlue = gamma + size * 2;
83705b261ecSmrg    crtc->gammaSize = size;
83805b261ecSmrg    return TRUE;
83905b261ecSmrg}
84005b261ecSmrg
8414642e01fSmrg/*
8424642e01fSmrg * Set the pending CRTC transformation
8434642e01fSmrg */
8444642e01fSmrg
8454642e01fSmrgint
84635c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc,
84735c4bbdfSmrg                   PictTransformPtr transform,
84835c4bbdfSmrg                   struct pixman_f_transform *f_transform,
84935c4bbdfSmrg                   struct pixman_f_transform *f_inverse,
85035c4bbdfSmrg                   char *filter_name,
85135c4bbdfSmrg                   int filter_len, xFixed * params, int nparams)
8524642e01fSmrg{
85335c4bbdfSmrg    PictFilterPtr filter = NULL;
85435c4bbdfSmrg    int width = 0, height = 0;
8554642e01fSmrg
8564642e01fSmrg    if (!crtc->transforms)
85735c4bbdfSmrg        return BadValue;
85835c4bbdfSmrg
85935c4bbdfSmrg    if (filter_len) {
86035c4bbdfSmrg        filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
86135c4bbdfSmrg        if (!filter)
86235c4bbdfSmrg            return BadName;
86335c4bbdfSmrg        if (filter->ValidateParams) {
86435c4bbdfSmrg            if (!filter->ValidateParams(crtc->pScreen, filter->id,
86535c4bbdfSmrg                                        params, nparams, &width, &height))
86635c4bbdfSmrg                return BadMatch;
86735c4bbdfSmrg        }
86835c4bbdfSmrg        else {
86935c4bbdfSmrg            width = filter->width;
87035c4bbdfSmrg            height = filter->height;
87135c4bbdfSmrg        }
8724642e01fSmrg    }
87335c4bbdfSmrg    else {
87435c4bbdfSmrg        if (nparams)
87535c4bbdfSmrg            return BadMatch;
8764642e01fSmrg    }
87735c4bbdfSmrg    if (!RRTransformSetFilter(&crtc->client_pending_transform,
87835c4bbdfSmrg                              filter, params, nparams, width, height))
87935c4bbdfSmrg        return BadAlloc;
8804642e01fSmrg
8814642e01fSmrg    crtc->client_pending_transform.transform = *transform;
8824642e01fSmrg    crtc->client_pending_transform.f_transform = *f_transform;
8834642e01fSmrg    crtc->client_pending_transform.f_inverse = *f_inverse;
8844642e01fSmrg    return Success;
8854642e01fSmrg}
8864642e01fSmrg
88705b261ecSmrg/*
88805b261ecSmrg * Initialize crtc type
88905b261ecSmrg */
89005b261ecSmrgBool
89135c4bbdfSmrgRRCrtcInit(void)
89205b261ecSmrg{
89335c4bbdfSmrg    RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
89405b261ecSmrg    if (!RRCrtcType)
89535c4bbdfSmrg        return FALSE;
89635c4bbdfSmrg
89705b261ecSmrg    return TRUE;
89805b261ecSmrg}
89905b261ecSmrg
9006747b715Smrg/*
9016747b715Smrg * Initialize crtc type error value
9026747b715Smrg */
9036747b715Smrgvoid
9046747b715SmrgRRCrtcInitErrorValue(void)
9056747b715Smrg{
9066747b715Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
9076747b715Smrg}
9086747b715Smrg
90905b261ecSmrgint
91035c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client)
91105b261ecSmrg{
91205b261ecSmrg    REQUEST(xRRGetCrtcInfoReq);
91335c4bbdfSmrg    xRRGetCrtcInfoReply rep;
91435c4bbdfSmrg    RRCrtcPtr crtc;
91535c4bbdfSmrg    CARD8 *extra;
91635c4bbdfSmrg    unsigned long extraLen;
91735c4bbdfSmrg    ScreenPtr pScreen;
91835c4bbdfSmrg    rrScrPrivPtr pScrPriv;
91935c4bbdfSmrg    RRModePtr mode;
92035c4bbdfSmrg    RROutput *outputs;
92135c4bbdfSmrg    RROutput *possible;
92235c4bbdfSmrg    int i, j, k;
92335c4bbdfSmrg    int width, height;
92435c4bbdfSmrg    BoxRec panned_area;
92535c4bbdfSmrg
92605b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
9276747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
92805b261ecSmrg
92905b261ecSmrg    /* All crtcs must be associated with screens before client
93005b261ecSmrg     * requests are processed
93105b261ecSmrg     */
93205b261ecSmrg    pScreen = crtc->pScreen;
93305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
93405b261ecSmrg
93505b261ecSmrg    mode = crtc->mode;
93635c4bbdfSmrg
93735c4bbdfSmrg    rep = (xRRGetCrtcInfoReply) {
93835c4bbdfSmrg        .type = X_Reply,
93935c4bbdfSmrg        .status = RRSetConfigSuccess,
94035c4bbdfSmrg        .sequenceNumber = client->sequence,
94135c4bbdfSmrg        .length = 0,
94235c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
94335c4bbdfSmrg    };
9444642e01fSmrg    if (pScrPriv->rrGetPanning &&
94535c4bbdfSmrg        pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
94635c4bbdfSmrg        (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
9474642e01fSmrg    {
94835c4bbdfSmrg        rep.x = panned_area.x1;
94935c4bbdfSmrg        rep.y = panned_area.y1;
95035c4bbdfSmrg        rep.width = panned_area.x2 - panned_area.x1;
95135c4bbdfSmrg        rep.height = panned_area.y2 - panned_area.y1;
9524642e01fSmrg    }
95335c4bbdfSmrg    else {
95435c4bbdfSmrg        RRCrtcGetScanoutSize(crtc, &width, &height);
95535c4bbdfSmrg        rep.x = crtc->x;
95635c4bbdfSmrg        rep.y = crtc->y;
95735c4bbdfSmrg        rep.width = width;
95835c4bbdfSmrg        rep.height = height;
9594642e01fSmrg    }
96005b261ecSmrg    rep.mode = mode ? mode->mode.id : 0;
96105b261ecSmrg    rep.rotation = crtc->rotation;
96205b261ecSmrg    rep.rotations = crtc->rotations;
96305b261ecSmrg    rep.nOutput = crtc->numOutputs;
96405b261ecSmrg    k = 0;
96505b261ecSmrg    for (i = 0; i < pScrPriv->numOutputs; i++)
96635c4bbdfSmrg        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
96735c4bbdfSmrg            if (pScrPriv->outputs[i]->crtcs[j] == crtc)
96835c4bbdfSmrg                k++;
96905b261ecSmrg    rep.nPossibleOutput = k;
97035c4bbdfSmrg
97105b261ecSmrg    rep.length = rep.nOutput + rep.nPossibleOutput;
97205b261ecSmrg
97305b261ecSmrg    extraLen = rep.length << 2;
97435c4bbdfSmrg    if (extraLen) {
97535c4bbdfSmrg        extra = malloc(extraLen);
97635c4bbdfSmrg        if (!extra)
97735c4bbdfSmrg            return BadAlloc;
97805b261ecSmrg    }
97905b261ecSmrg    else
98035c4bbdfSmrg        extra = NULL;
98105b261ecSmrg
98205b261ecSmrg    outputs = (RROutput *) extra;
98305b261ecSmrg    possible = (RROutput *) (outputs + rep.nOutput);
98435c4bbdfSmrg
98535c4bbdfSmrg    for (i = 0; i < crtc->numOutputs; i++) {
98635c4bbdfSmrg        outputs[i] = crtc->outputs[i]->id;
98735c4bbdfSmrg        if (client->swapped)
98835c4bbdfSmrg            swapl(&outputs[i]);
98905b261ecSmrg    }
99005b261ecSmrg    k = 0;
99105b261ecSmrg    for (i = 0; i < pScrPriv->numOutputs; i++)
99235c4bbdfSmrg        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
99335c4bbdfSmrg            if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
99435c4bbdfSmrg                possible[k] = pScrPriv->outputs[i]->id;
99535c4bbdfSmrg                if (client->swapped)
99635c4bbdfSmrg                    swapl(&possible[k]);
99735c4bbdfSmrg                k++;
99835c4bbdfSmrg            }
99935c4bbdfSmrg
100005b261ecSmrg    if (client->swapped) {
100135c4bbdfSmrg        swaps(&rep.sequenceNumber);
100235c4bbdfSmrg        swapl(&rep.length);
100335c4bbdfSmrg        swapl(&rep.timestamp);
100435c4bbdfSmrg        swaps(&rep.x);
100535c4bbdfSmrg        swaps(&rep.y);
100635c4bbdfSmrg        swaps(&rep.width);
100735c4bbdfSmrg        swaps(&rep.height);
100835c4bbdfSmrg        swapl(&rep.mode);
100935c4bbdfSmrg        swaps(&rep.rotation);
101035c4bbdfSmrg        swaps(&rep.rotations);
101135c4bbdfSmrg        swaps(&rep.nOutput);
101235c4bbdfSmrg        swaps(&rep.nPossibleOutput);
101335c4bbdfSmrg    }
101435c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
101535c4bbdfSmrg    if (extraLen) {
101635c4bbdfSmrg        WriteToClient(client, extraLen, extra);
101735c4bbdfSmrg        free(extra);
101805b261ecSmrg    }
101935c4bbdfSmrg
10206747b715Smrg    return Success;
102105b261ecSmrg}
102205b261ecSmrg
102305b261ecSmrgint
102435c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client)
102505b261ecSmrg{
102605b261ecSmrg    REQUEST(xRRSetCrtcConfigReq);
102735c4bbdfSmrg    xRRSetCrtcConfigReply rep;
102835c4bbdfSmrg    ScreenPtr pScreen;
102935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
103035c4bbdfSmrg    RRCrtcPtr crtc;
103135c4bbdfSmrg    RRModePtr mode;
103235c4bbdfSmrg    int numOutputs;
103335c4bbdfSmrg    RROutputPtr *outputs = NULL;
103435c4bbdfSmrg    RROutput *outputIds;
103535c4bbdfSmrg    TimeStamp time;
103635c4bbdfSmrg    Rotation rotation;
103735c4bbdfSmrg    int ret, i, j;
103835c4bbdfSmrg    CARD8 status;
103935c4bbdfSmrg
104005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
104135c4bbdfSmrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
104235c4bbdfSmrg
10436747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
10446747b715Smrg
104535c4bbdfSmrg    if (stuff->mode == None) {
104635c4bbdfSmrg        mode = NULL;
104735c4bbdfSmrg        if (numOutputs > 0)
104835c4bbdfSmrg            return BadMatch;
104905b261ecSmrg    }
105035c4bbdfSmrg    else {
105135c4bbdfSmrg        VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
105235c4bbdfSmrg        if (numOutputs == 0)
105335c4bbdfSmrg            return BadMatch;
105405b261ecSmrg    }
105535c4bbdfSmrg    if (numOutputs) {
105635c4bbdfSmrg        outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
105735c4bbdfSmrg        if (!outputs)
105835c4bbdfSmrg            return BadAlloc;
105905b261ecSmrg    }
106005b261ecSmrg    else
106135c4bbdfSmrg        outputs = NULL;
106235c4bbdfSmrg
106305b261ecSmrg    outputIds = (RROutput *) (stuff + 1);
106435c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
106535c4bbdfSmrg        ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
106635c4bbdfSmrg                                     RROutputType, client, DixSetAttrAccess);
106735c4bbdfSmrg        if (ret != Success) {
106835c4bbdfSmrg            free(outputs);
106935c4bbdfSmrg            return ret;
107035c4bbdfSmrg        }
107135c4bbdfSmrg        /* validate crtc for this output */
107235c4bbdfSmrg        for (j = 0; j < outputs[i]->numCrtcs; j++)
107335c4bbdfSmrg            if (outputs[i]->crtcs[j] == crtc)
107435c4bbdfSmrg                break;
107535c4bbdfSmrg        if (j == outputs[i]->numCrtcs) {
107635c4bbdfSmrg            free(outputs);
107735c4bbdfSmrg            return BadMatch;
107835c4bbdfSmrg        }
107935c4bbdfSmrg        /* validate mode for this output */
108035c4bbdfSmrg        for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
108135c4bbdfSmrg            RRModePtr m = (j < outputs[i]->numModes ?
108235c4bbdfSmrg                           outputs[i]->modes[j] :
108335c4bbdfSmrg                           outputs[i]->userModes[j - outputs[i]->numModes]);
108435c4bbdfSmrg            if (m == mode)
108535c4bbdfSmrg                break;
108635c4bbdfSmrg        }
108735c4bbdfSmrg        if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
108835c4bbdfSmrg            free(outputs);
108935c4bbdfSmrg            return BadMatch;
109035c4bbdfSmrg        }
109105b261ecSmrg    }
109205b261ecSmrg    /* validate clones */
109335c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
109435c4bbdfSmrg        for (j = 0; j < numOutputs; j++) {
109535c4bbdfSmrg            int k;
109635c4bbdfSmrg
109735c4bbdfSmrg            if (i == j)
109835c4bbdfSmrg                continue;
109935c4bbdfSmrg            for (k = 0; k < outputs[i]->numClones; k++) {
110035c4bbdfSmrg                if (outputs[i]->clones[k] == outputs[j])
110135c4bbdfSmrg                    break;
110235c4bbdfSmrg            }
110335c4bbdfSmrg            if (k == outputs[i]->numClones) {
110435c4bbdfSmrg                free(outputs);
110535c4bbdfSmrg                return BadMatch;
110635c4bbdfSmrg            }
110735c4bbdfSmrg        }
110805b261ecSmrg    }
110905b261ecSmrg
111005b261ecSmrg    pScreen = crtc->pScreen;
111105b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
111235c4bbdfSmrg
111305b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
111435c4bbdfSmrg
111535c4bbdfSmrg    if (!pScrPriv) {
111635c4bbdfSmrg        time = currentTime;
111735c4bbdfSmrg        status = RRSetConfigFailed;
111835c4bbdfSmrg        goto sendReply;
111905b261ecSmrg    }
112035c4bbdfSmrg
112105b261ecSmrg    /*
112205b261ecSmrg     * Validate requested rotation
112305b261ecSmrg     */
112405b261ecSmrg    rotation = (Rotation) stuff->rotation;
112505b261ecSmrg
112605b261ecSmrg    /* test the rotation bits only! */
112705b261ecSmrg    switch (rotation & 0xf) {
112805b261ecSmrg    case RR_Rotate_0:
112905b261ecSmrg    case RR_Rotate_90:
113005b261ecSmrg    case RR_Rotate_180:
113105b261ecSmrg    case RR_Rotate_270:
113235c4bbdfSmrg        break;
113305b261ecSmrg    default:
113435c4bbdfSmrg        /*
113535c4bbdfSmrg         * Invalid rotation
113635c4bbdfSmrg         */
113735c4bbdfSmrg        client->errorValue = stuff->rotation;
113835c4bbdfSmrg        free(outputs);
113935c4bbdfSmrg        return BadValue;
114005b261ecSmrg    }
114105b261ecSmrg
114235c4bbdfSmrg    if (mode) {
114335c4bbdfSmrg        if ((~crtc->rotations) & rotation) {
114435c4bbdfSmrg            /*
114535c4bbdfSmrg             * requested rotation or reflection not supported by screen
114635c4bbdfSmrg             */
114735c4bbdfSmrg            client->errorValue = stuff->rotation;
114835c4bbdfSmrg            free(outputs);
114935c4bbdfSmrg            return BadMatch;
115035c4bbdfSmrg        }
115135c4bbdfSmrg
115205b261ecSmrg#ifdef RANDR_12_INTERFACE
115335c4bbdfSmrg        /*
115435c4bbdfSmrg         * Check screen size bounds if the DDX provides a 1.2 interface
115535c4bbdfSmrg         * for setting screen size. Else, assume the CrtcSet sets
115635c4bbdfSmrg         * the size along with the mode. If the driver supports transforms,
115735c4bbdfSmrg         * then it must allow crtcs to display a subset of the screen, so
115835c4bbdfSmrg         * only do this check for drivers without transform support.
115935c4bbdfSmrg         */
116035c4bbdfSmrg        if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
116135c4bbdfSmrg            int source_width;
116235c4bbdfSmrg            int source_height;
116335c4bbdfSmrg            PictTransform transform;
116435c4bbdfSmrg            struct pixman_f_transform f_transform, f_inverse;
116535c4bbdfSmrg            int width, height;
116635c4bbdfSmrg
116735c4bbdfSmrg            if (pScreen->isGPU) {
116835c4bbdfSmrg                width = pScreen->current_master->width;
116935c4bbdfSmrg                height = pScreen->current_master->height;
117035c4bbdfSmrg            }
117135c4bbdfSmrg            else {
117235c4bbdfSmrg                width = pScreen->width;
117335c4bbdfSmrg                height = pScreen->height;
117435c4bbdfSmrg            }
117535c4bbdfSmrg
117635c4bbdfSmrg            RRTransformCompute(stuff->x, stuff->y,
117735c4bbdfSmrg                               mode->mode.width, mode->mode.height,
117835c4bbdfSmrg                               rotation,
117935c4bbdfSmrg                               &crtc->client_pending_transform,
118035c4bbdfSmrg                               &transform, &f_transform, &f_inverse);
118135c4bbdfSmrg
118235c4bbdfSmrg            RRModeGetScanoutSize(mode, &transform, &source_width,
118335c4bbdfSmrg                                 &source_height);
118435c4bbdfSmrg            if (stuff->x + source_width > width) {
118535c4bbdfSmrg                client->errorValue = stuff->x;
118635c4bbdfSmrg                free(outputs);
118735c4bbdfSmrg                return BadValue;
118835c4bbdfSmrg            }
118935c4bbdfSmrg
119035c4bbdfSmrg            if (stuff->y + source_height > height) {
119135c4bbdfSmrg                client->errorValue = stuff->y;
119235c4bbdfSmrg                free(outputs);
119335c4bbdfSmrg                return BadValue;
119435c4bbdfSmrg            }
119535c4bbdfSmrg        }
119605b261ecSmrg#endif
119705b261ecSmrg    }
119835c4bbdfSmrg
119935c4bbdfSmrg    if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
120035c4bbdfSmrg                   rotation, numOutputs, outputs)) {
120135c4bbdfSmrg        status = RRSetConfigFailed;
120235c4bbdfSmrg        goto sendReply;
120305b261ecSmrg    }
120435c4bbdfSmrg    status = RRSetConfigSuccess;
120552397711Smrg    pScrPriv->lastSetTime = time;
120635c4bbdfSmrg
120735c4bbdfSmrg sendReply:
12086747b715Smrg    free(outputs);
120935c4bbdfSmrg
121035c4bbdfSmrg    rep = (xRRSetCrtcConfigReply) {
121135c4bbdfSmrg        .type = X_Reply,
121235c4bbdfSmrg        .status = status,
121335c4bbdfSmrg        .sequenceNumber = client->sequence,
121435c4bbdfSmrg        .length = 0,
121535c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
121635c4bbdfSmrg    };
121735c4bbdfSmrg
121835c4bbdfSmrg    if (client->swapped) {
121935c4bbdfSmrg        swaps(&rep.sequenceNumber);
122035c4bbdfSmrg        swapl(&rep.length);
122135c4bbdfSmrg        swapl(&rep.newTimestamp);
122205b261ecSmrg    }
122335c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
122435c4bbdfSmrg
12256747b715Smrg    return Success;
122605b261ecSmrg}
122705b261ecSmrg
12284642e01fSmrgint
122935c4bbdfSmrgProcRRGetPanning(ClientPtr client)
12304642e01fSmrg{
12314642e01fSmrg    REQUEST(xRRGetPanningReq);
123235c4bbdfSmrg    xRRGetPanningReply rep;
123335c4bbdfSmrg    RRCrtcPtr crtc;
123435c4bbdfSmrg    ScreenPtr pScreen;
123535c4bbdfSmrg    rrScrPrivPtr pScrPriv;
123635c4bbdfSmrg    BoxRec total;
123735c4bbdfSmrg    BoxRec tracking;
123835c4bbdfSmrg    INT16 border[4];
123935c4bbdfSmrg
12404642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
12416747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
12424642e01fSmrg
12434642e01fSmrg    /* All crtcs must be associated with screens before client
12444642e01fSmrg     * requests are processed
12454642e01fSmrg     */
12464642e01fSmrg    pScreen = crtc->pScreen;
12474642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
12484642e01fSmrg
12494642e01fSmrg    if (!pScrPriv)
125035c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
12514642e01fSmrg
125235c4bbdfSmrg    rep = (xRRGetPanningReply) {
125335c4bbdfSmrg        .type = X_Reply,
125435c4bbdfSmrg        .status = RRSetConfigSuccess,
125535c4bbdfSmrg        .sequenceNumber = client->sequence,
125635c4bbdfSmrg        .length = 1,
125735c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
125835c4bbdfSmrg    };
12594642e01fSmrg
12604642e01fSmrg    if (pScrPriv->rrGetPanning &&
126135c4bbdfSmrg        pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
126235c4bbdfSmrg        rep.left = total.x1;
126335c4bbdfSmrg        rep.top = total.y1;
126435c4bbdfSmrg        rep.width = total.x2 - total.x1;
126535c4bbdfSmrg        rep.height = total.y2 - total.y1;
126635c4bbdfSmrg        rep.track_left = tracking.x1;
126735c4bbdfSmrg        rep.track_top = tracking.y1;
126835c4bbdfSmrg        rep.track_width = tracking.x2 - tracking.x1;
126935c4bbdfSmrg        rep.track_height = tracking.y2 - tracking.y1;
127035c4bbdfSmrg        rep.border_left = border[0];
127135c4bbdfSmrg        rep.border_top = border[1];
127235c4bbdfSmrg        rep.border_right = border[2];
127335c4bbdfSmrg        rep.border_bottom = border[3];
12744642e01fSmrg    }
12754642e01fSmrg
12764642e01fSmrg    if (client->swapped) {
127735c4bbdfSmrg        swaps(&rep.sequenceNumber);
127835c4bbdfSmrg        swapl(&rep.length);
127935c4bbdfSmrg        swapl(&rep.timestamp);
128035c4bbdfSmrg        swaps(&rep.left);
128135c4bbdfSmrg        swaps(&rep.top);
128235c4bbdfSmrg        swaps(&rep.width);
128335c4bbdfSmrg        swaps(&rep.height);
128435c4bbdfSmrg        swaps(&rep.track_left);
128535c4bbdfSmrg        swaps(&rep.track_top);
128635c4bbdfSmrg        swaps(&rep.track_width);
128735c4bbdfSmrg        swaps(&rep.track_height);
128835c4bbdfSmrg        swaps(&rep.border_left);
128935c4bbdfSmrg        swaps(&rep.border_top);
129035c4bbdfSmrg        swaps(&rep.border_right);
129135c4bbdfSmrg        swaps(&rep.border_bottom);
129235c4bbdfSmrg    }
129335c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
12946747b715Smrg    return Success;
12954642e01fSmrg}
12964642e01fSmrg
12974642e01fSmrgint
129835c4bbdfSmrgProcRRSetPanning(ClientPtr client)
12994642e01fSmrg{
13004642e01fSmrg    REQUEST(xRRSetPanningReq);
130135c4bbdfSmrg    xRRSetPanningReply rep;
130235c4bbdfSmrg    RRCrtcPtr crtc;
130335c4bbdfSmrg    ScreenPtr pScreen;
130435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
130535c4bbdfSmrg    TimeStamp time;
130635c4bbdfSmrg    BoxRec total;
130735c4bbdfSmrg    BoxRec tracking;
130835c4bbdfSmrg    INT16 border[4];
130935c4bbdfSmrg    CARD8 status;
131035c4bbdfSmrg
13114642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
13126747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
13134642e01fSmrg
13144642e01fSmrg    /* All crtcs must be associated with screens before client
13154642e01fSmrg     * requests are processed
13164642e01fSmrg     */
13174642e01fSmrg    pScreen = crtc->pScreen;
13184642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
13194642e01fSmrg
13204642e01fSmrg    if (!pScrPriv) {
132135c4bbdfSmrg        time = currentTime;
132235c4bbdfSmrg        status = RRSetConfigFailed;
132335c4bbdfSmrg        goto sendReply;
13244642e01fSmrg    }
132535c4bbdfSmrg
13264642e01fSmrg    time = ClientTimeToServerTime(stuff->timestamp);
132735c4bbdfSmrg
13284642e01fSmrg    if (!pScrPriv->rrGetPanning)
132935c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
13304642e01fSmrg
133135c4bbdfSmrg    total.x1 = stuff->left;
133235c4bbdfSmrg    total.y1 = stuff->top;
133335c4bbdfSmrg    total.x2 = total.x1 + stuff->width;
133435c4bbdfSmrg    total.y2 = total.y1 + stuff->height;
13354642e01fSmrg    tracking.x1 = stuff->track_left;
13364642e01fSmrg    tracking.y1 = stuff->track_top;
13374642e01fSmrg    tracking.x2 = tracking.x1 + stuff->track_width;
13384642e01fSmrg    tracking.y2 = tracking.y1 + stuff->track_height;
133935c4bbdfSmrg    border[0] = stuff->border_left;
134035c4bbdfSmrg    border[1] = stuff->border_top;
134135c4bbdfSmrg    border[2] = stuff->border_right;
134235c4bbdfSmrg    border[3] = stuff->border_bottom;
13434642e01fSmrg
134435c4bbdfSmrg    if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
134535c4bbdfSmrg        return BadMatch;
13464642e01fSmrg
134752397711Smrg    pScrPriv->lastSetTime = time;
134852397711Smrg
134935c4bbdfSmrg    status = RRSetConfigSuccess;
13504642e01fSmrg
135135c4bbdfSmrg sendReply:
135235c4bbdfSmrg    rep = (xRRSetPanningReply) {
135335c4bbdfSmrg        .type = X_Reply,
135435c4bbdfSmrg        .status = status,
135535c4bbdfSmrg        .sequenceNumber = client->sequence,
135635c4bbdfSmrg        .length = 0,
135735c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
135835c4bbdfSmrg    };
13594642e01fSmrg
13604642e01fSmrg    if (client->swapped) {
136135c4bbdfSmrg        swaps(&rep.sequenceNumber);
136235c4bbdfSmrg        swapl(&rep.length);
136335c4bbdfSmrg        swapl(&rep.newTimestamp);
13644642e01fSmrg    }
136535c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
13666747b715Smrg    return Success;
13674642e01fSmrg}
13684642e01fSmrg
136905b261ecSmrgint
137035c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client)
137105b261ecSmrg{
137205b261ecSmrg    REQUEST(xRRGetCrtcGammaSizeReq);
137335c4bbdfSmrg    xRRGetCrtcGammaSizeReply reply;
137435c4bbdfSmrg    RRCrtcPtr crtc;
137505b261ecSmrg
137605b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
13776747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
13786747b715Smrg
13796747b715Smrg    /* Gamma retrieval failed, any better error? */
13806747b715Smrg    if (!RRCrtcGammaGet(crtc))
13816747b715Smrg        return RRErrorBase + BadRRCrtc;
13826747b715Smrg
138335c4bbdfSmrg    reply = (xRRGetCrtcGammaSizeReply) {
138435c4bbdfSmrg        .type = X_Reply,
138535c4bbdfSmrg        .sequenceNumber = client->sequence,
138635c4bbdfSmrg        .length = 0,
138735c4bbdfSmrg        .size = crtc->gammaSize
138835c4bbdfSmrg    };
138905b261ecSmrg    if (client->swapped) {
139035c4bbdfSmrg        swaps(&reply.sequenceNumber);
139135c4bbdfSmrg        swapl(&reply.length);
139235c4bbdfSmrg        swaps(&reply.size);
139305b261ecSmrg    }
139435c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
13956747b715Smrg    return Success;
139605b261ecSmrg}
139705b261ecSmrg
139805b261ecSmrgint
139935c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client)
140005b261ecSmrg{
140105b261ecSmrg    REQUEST(xRRGetCrtcGammaReq);
140235c4bbdfSmrg    xRRGetCrtcGammaReply reply;
140335c4bbdfSmrg    RRCrtcPtr crtc;
140435c4bbdfSmrg    unsigned long len;
140535c4bbdfSmrg    char *extra = NULL;
140635c4bbdfSmrg
140705b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
14086747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
14096747b715Smrg
14106747b715Smrg    /* Gamma retrieval failed, any better error? */
14116747b715Smrg    if (!RRCrtcGammaGet(crtc))
14126747b715Smrg        return RRErrorBase + BadRRCrtc;
14136747b715Smrg
141405b261ecSmrg    len = crtc->gammaSize * 3 * 2;
141535c4bbdfSmrg
14164642e01fSmrg    if (crtc->gammaSize) {
141735c4bbdfSmrg        extra = malloc(len);
141835c4bbdfSmrg        if (!extra)
141935c4bbdfSmrg            return BadAlloc;
14204642e01fSmrg    }
14214642e01fSmrg
142235c4bbdfSmrg    reply = (xRRGetCrtcGammaReply) {
142335c4bbdfSmrg        .type = X_Reply,
142435c4bbdfSmrg        .sequenceNumber = client->sequence,
142535c4bbdfSmrg        .length = bytes_to_int32(len),
142635c4bbdfSmrg        .size = crtc->gammaSize
142735c4bbdfSmrg    };
142805b261ecSmrg    if (client->swapped) {
142935c4bbdfSmrg        swaps(&reply.sequenceNumber);
143035c4bbdfSmrg        swapl(&reply.length);
143135c4bbdfSmrg        swaps(&reply.size);
143205b261ecSmrg    }
143335c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
143435c4bbdfSmrg    if (crtc->gammaSize) {
143535c4bbdfSmrg        memcpy(extra, crtc->gammaRed, len);
143635c4bbdfSmrg        client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
143735c4bbdfSmrg        WriteSwappedDataToClient(client, len, extra);
143835c4bbdfSmrg        free(extra);
143905b261ecSmrg    }
14406747b715Smrg    return Success;
144105b261ecSmrg}
144205b261ecSmrg
144305b261ecSmrgint
144435c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client)
144505b261ecSmrg{
144605b261ecSmrg    REQUEST(xRRSetCrtcGammaReq);
144735c4bbdfSmrg    RRCrtcPtr crtc;
144835c4bbdfSmrg    unsigned long len;
144935c4bbdfSmrg    CARD16 *red, *green, *blue;
145035c4bbdfSmrg
145105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
14526747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
145335c4bbdfSmrg
145435c4bbdfSmrg    len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
145505b261ecSmrg    if (len < (stuff->size * 3 + 1) >> 1)
145635c4bbdfSmrg        return BadLength;
145705b261ecSmrg
145805b261ecSmrg    if (stuff->size != crtc->gammaSize)
145935c4bbdfSmrg        return BadMatch;
146035c4bbdfSmrg
146105b261ecSmrg    red = (CARD16 *) (stuff + 1);
146205b261ecSmrg    green = red + crtc->gammaSize;
146305b261ecSmrg    blue = green + crtc->gammaSize;
146435c4bbdfSmrg
146535c4bbdfSmrg    RRCrtcGammaSet(crtc, red, green, blue);
146605b261ecSmrg
146705b261ecSmrg    return Success;
146805b261ecSmrg}
146905b261ecSmrg
14704642e01fSmrg/* Version 1.3 additions */
14714642e01fSmrg
14724642e01fSmrgint
147335c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client)
14744642e01fSmrg{
14754642e01fSmrg    REQUEST(xRRSetCrtcTransformReq);
147635c4bbdfSmrg    RRCrtcPtr crtc;
147735c4bbdfSmrg    PictTransform transform;
14784642e01fSmrg    struct pixman_f_transform f_transform, f_inverse;
147935c4bbdfSmrg    char *filter;
148035c4bbdfSmrg    int nbytes;
148135c4bbdfSmrg    xFixed *params;
148235c4bbdfSmrg    int nparams;
14834642e01fSmrg
14844642e01fSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
14856747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
14864642e01fSmrg
148735c4bbdfSmrg    PictTransform_from_xRenderTransform(&transform, &stuff->transform);
148835c4bbdfSmrg    pixman_f_transform_from_pixman_transform(&f_transform, &transform);
148935c4bbdfSmrg    if (!pixman_f_transform_invert(&f_inverse, &f_transform))
149035c4bbdfSmrg        return BadMatch;
14914642e01fSmrg
14924642e01fSmrg    filter = (char *) (stuff + 1);
14934642e01fSmrg    nbytes = stuff->nbytesFilter;
14946747b715Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
14954642e01fSmrg    nparams = ((xFixed *) stuff + client->req_len) - params;
14964642e01fSmrg    if (nparams < 0)
149735c4bbdfSmrg        return BadLength;
14984642e01fSmrg
149935c4bbdfSmrg    return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
150035c4bbdfSmrg                              filter, nbytes, params, nparams);
15014642e01fSmrg}
15024642e01fSmrg
15034642e01fSmrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
150435c4bbdfSmrg
15054642e01fSmrgstatic int
150635c4bbdfSmrgtransform_filter_length(RRTransformPtr transform)
15074642e01fSmrg{
150835c4bbdfSmrg    int nbytes, nparams;
15094642e01fSmrg
15104642e01fSmrg    if (transform->filter == NULL)
151135c4bbdfSmrg        return 0;
151235c4bbdfSmrg    nbytes = strlen(transform->filter->name);
15134642e01fSmrg    nparams = transform->nparams;
151435c4bbdfSmrg    return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
15154642e01fSmrg}
15164642e01fSmrg
15174642e01fSmrgstatic int
151835c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output,
151935c4bbdfSmrg                        CARD16 *nbytesFilter,
152035c4bbdfSmrg                        CARD16 *nparamsFilter, RRTransformPtr transform)
15214642e01fSmrg{
152235c4bbdfSmrg    int nbytes, nparams;
15234642e01fSmrg
15244642e01fSmrg    if (transform->filter == NULL) {
152535c4bbdfSmrg        *nbytesFilter = 0;
152635c4bbdfSmrg        *nparamsFilter = 0;
152735c4bbdfSmrg        return 0;
15284642e01fSmrg    }
152935c4bbdfSmrg    nbytes = strlen(transform->filter->name);
15304642e01fSmrg    nparams = transform->nparams;
15314642e01fSmrg    *nbytesFilter = nbytes;
15324642e01fSmrg    *nparamsFilter = nparams;
153335c4bbdfSmrg    memcpy(output, transform->filter->name, nbytes);
15344642e01fSmrg    while ((nbytes & 3) != 0)
153535c4bbdfSmrg        output[nbytes++] = 0;
153635c4bbdfSmrg    memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
15374642e01fSmrg    if (client->swapped) {
153835c4bbdfSmrg        swaps(nbytesFilter);
153935c4bbdfSmrg        swaps(nparamsFilter);
154035c4bbdfSmrg        SwapLongs((CARD32 *) (output + nbytes), nparams);
15414642e01fSmrg    }
154235c4bbdfSmrg    nbytes += nparams * sizeof(xFixed);
15434642e01fSmrg    return nbytes;
15444642e01fSmrg}
15454642e01fSmrg
15464642e01fSmrgstatic void
154735c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire,
154835c4bbdfSmrg                 PictTransform * pict)
15494642e01fSmrg{
155035c4bbdfSmrg    xRenderTransform_from_PictTransform(wire, pict);
15514642e01fSmrg    if (client->swapped)
155235c4bbdfSmrg        SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
15534642e01fSmrg}
15544642e01fSmrg
15554642e01fSmrgint
155635c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client)
15574642e01fSmrg{
15584642e01fSmrg    REQUEST(xRRGetCrtcTransformReq);
155935c4bbdfSmrg    xRRGetCrtcTransformReply *reply;
156035c4bbdfSmrg    RRCrtcPtr crtc;
156135c4bbdfSmrg    int nextra;
156235c4bbdfSmrg    RRTransformPtr current, pending;
156335c4bbdfSmrg    char *extra;
15644642e01fSmrg
156535c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
15666747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15674642e01fSmrg
15684642e01fSmrg    pending = &crtc->client_pending_transform;
15694642e01fSmrg    current = &crtc->client_current_transform;
15704642e01fSmrg
157135c4bbdfSmrg    nextra = (transform_filter_length(pending) +
157235c4bbdfSmrg              transform_filter_length(current));
15734642e01fSmrg
157435c4bbdfSmrg    reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
15754642e01fSmrg    if (!reply)
157635c4bbdfSmrg        return BadAlloc;
15774642e01fSmrg
15784642e01fSmrg    extra = (char *) (reply + 1);
15794642e01fSmrg    reply->type = X_Reply;
15804642e01fSmrg    reply->sequenceNumber = client->sequence;
15816747b715Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
15824642e01fSmrg
15834642e01fSmrg    reply->hasTransforms = crtc->transforms;
15844642e01fSmrg
158535c4bbdfSmrg    transform_encode(client, &reply->pendingTransform, &pending->transform);
158635c4bbdfSmrg    extra += transform_filter_encode(client, extra,
158735c4bbdfSmrg                                     &reply->pendingNbytesFilter,
158835c4bbdfSmrg                                     &reply->pendingNparamsFilter, pending);
15894642e01fSmrg
159035c4bbdfSmrg    transform_encode(client, &reply->currentTransform, &current->transform);
159135c4bbdfSmrg    extra += transform_filter_encode(client, extra,
159235c4bbdfSmrg                                     &reply->currentNbytesFilter,
159335c4bbdfSmrg                                     &reply->currentNparamsFilter, current);
15944642e01fSmrg
15954642e01fSmrg    if (client->swapped) {
159635c4bbdfSmrg        swaps(&reply->sequenceNumber);
159735c4bbdfSmrg        swapl(&reply->length);
15984642e01fSmrg    }
159935c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
16006747b715Smrg    free(reply);
16016747b715Smrg    return Success;
16024642e01fSmrg}
160335c4bbdfSmrg
160435c4bbdfSmrgstatic Bool
160535c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
160635c4bbdfSmrg{
160735c4bbdfSmrg    rrScrPriv(pScreen);
160835c4bbdfSmrg    int i;
160935c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
161035c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
161135c4bbdfSmrg
161235c4bbdfSmrg        int left, right, top, bottom;
161335c4bbdfSmrg
161435c4bbdfSmrg        if (!crtc->mode)
161535c4bbdfSmrg            continue;
161635c4bbdfSmrg
161735c4bbdfSmrg        crtc_bounds(crtc, &left, &right, &top, &bottom);
161835c4bbdfSmrg
161935c4bbdfSmrg        if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
162035c4bbdfSmrg            return TRUE;
162135c4bbdfSmrg    }
162235c4bbdfSmrg    return FALSE;
162335c4bbdfSmrg}
162435c4bbdfSmrg
162535c4bbdfSmrgstatic Bool
162635c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
162735c4bbdfSmrg{
162835c4bbdfSmrg    rrScrPriv(pScreen);
162935c4bbdfSmrg    int i;
163035c4bbdfSmrg
163135c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
163235c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
163335c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
163435c4bbdfSmrg        int nx, ny;
163535c4bbdfSmrg        int left, right, top, bottom;
163635c4bbdfSmrg
163735c4bbdfSmrg        if (!crtc->mode)
163835c4bbdfSmrg            continue;
163935c4bbdfSmrg
164035c4bbdfSmrg        crtc_bounds(crtc, &left, &right, &top, &bottom);
164135c4bbdfSmrg        miPointerGetPosition(pDev, &nx, &ny);
164235c4bbdfSmrg
164335c4bbdfSmrg        if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
164435c4bbdfSmrg            if (*x < left)
164535c4bbdfSmrg                *x = left;
164635c4bbdfSmrg            if (*x >= right)
164735c4bbdfSmrg                *x = right - 1;
164835c4bbdfSmrg            if (*y < top)
164935c4bbdfSmrg                *y = top;
165035c4bbdfSmrg            if (*y >= bottom)
165135c4bbdfSmrg                *y = bottom - 1;
165235c4bbdfSmrg
165335c4bbdfSmrg            return TRUE;
165435c4bbdfSmrg        }
165535c4bbdfSmrg    }
165635c4bbdfSmrg    return FALSE;
165735c4bbdfSmrg}
165835c4bbdfSmrg
165935c4bbdfSmrgvoid
166035c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
166135c4bbdfSmrg                        int *y)
166235c4bbdfSmrg{
166335c4bbdfSmrg    rrScrPriv(pScreen);
166435c4bbdfSmrg    Bool ret;
166535c4bbdfSmrg    ScreenPtr slave;
166635c4bbdfSmrg
166735c4bbdfSmrg    /* intentional dead space -> let it float */
166835c4bbdfSmrg    if (pScrPriv->discontiguous)
166935c4bbdfSmrg        return;
167035c4bbdfSmrg
167135c4bbdfSmrg    /* if we're moving inside a crtc, we're fine */
167235c4bbdfSmrg    ret = check_all_screen_crtcs(pScreen, x, y);
167335c4bbdfSmrg    if (ret == TRUE)
167435c4bbdfSmrg        return;
167535c4bbdfSmrg
167635c4bbdfSmrg    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
167735c4bbdfSmrg        ret = check_all_screen_crtcs(slave, x, y);
167835c4bbdfSmrg        if (ret == TRUE)
167935c4bbdfSmrg            return;
168035c4bbdfSmrg    }
168135c4bbdfSmrg
168235c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
168335c4bbdfSmrg    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
168435c4bbdfSmrg    if (ret == TRUE)
168535c4bbdfSmrg        return;
168635c4bbdfSmrg
168735c4bbdfSmrg    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
168835c4bbdfSmrg        ret = constrain_all_screen_crtcs(pDev, slave, x, y);
168935c4bbdfSmrg        if (ret == TRUE)
169035c4bbdfSmrg            return;
169135c4bbdfSmrg    }
169235c4bbdfSmrg}
169335c4bbdfSmrg
169435c4bbdfSmrgBool
169535c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
169635c4bbdfSmrg{
169735c4bbdfSmrg    rrScrPriv(pDrawable->pScreen);
169835c4bbdfSmrg    Bool ret = TRUE;
169935c4bbdfSmrg    PixmapPtr *saved_scanout_pixmap;
170035c4bbdfSmrg    int i;
170135c4bbdfSmrg
170235c4bbdfSmrg    saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
170335c4bbdfSmrg    if (saved_scanout_pixmap == NULL)
170435c4bbdfSmrg        return FALSE;
170535c4bbdfSmrg
170635c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
170735c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
170835c4bbdfSmrg        Bool size_fits;
170935c4bbdfSmrg
171035c4bbdfSmrg        saved_scanout_pixmap[i] = crtc->scanout_pixmap;
171135c4bbdfSmrg
171235c4bbdfSmrg        if (!crtc->mode && enable)
171335c4bbdfSmrg            continue;
171435c4bbdfSmrg        if (!crtc->scanout_pixmap && !enable)
171535c4bbdfSmrg            continue;
171635c4bbdfSmrg
171735c4bbdfSmrg        size_fits = (crtc->mode &&
171835c4bbdfSmrg                     crtc->x == pDrawable->x &&
171935c4bbdfSmrg                     crtc->y == pDrawable->y &&
172035c4bbdfSmrg                     crtc->mode->mode.width == pDrawable->width &&
172135c4bbdfSmrg                     crtc->mode->mode.height == pDrawable->height);
172235c4bbdfSmrg
172335c4bbdfSmrg        /* is the pixmap already set? */
172435c4bbdfSmrg        if (crtc->scanout_pixmap == pPixmap) {
172535c4bbdfSmrg            /* if its a disable then don't care about size */
172635c4bbdfSmrg            if (enable == FALSE) {
172735c4bbdfSmrg                /* set scanout to NULL */
172835c4bbdfSmrg                crtc->scanout_pixmap = NULL;
172935c4bbdfSmrg            }
173035c4bbdfSmrg            else if (!size_fits) {
173135c4bbdfSmrg                /* if the size no longer fits then drop off */
173235c4bbdfSmrg                crtc->scanout_pixmap = NULL;
173335c4bbdfSmrg                pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
173435c4bbdfSmrg
173535c4bbdfSmrg                (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
173635c4bbdfSmrg                                        crtc->rotation, crtc->numOutputs, crtc->outputs);
173735c4bbdfSmrg                saved_scanout_pixmap[i] = crtc->scanout_pixmap;
173835c4bbdfSmrg                ret = FALSE;
173935c4bbdfSmrg            }
174035c4bbdfSmrg            else {
174135c4bbdfSmrg                /* if the size fits then we are already setup */
174235c4bbdfSmrg            }
174335c4bbdfSmrg        }
174435c4bbdfSmrg        else {
174535c4bbdfSmrg            if (!size_fits)
174635c4bbdfSmrg                ret = FALSE;
174735c4bbdfSmrg            else if (enable)
174835c4bbdfSmrg                crtc->scanout_pixmap = pPixmap;
174935c4bbdfSmrg            else
175035c4bbdfSmrg                /* reject an attempt to disable someone else's scanout_pixmap */
175135c4bbdfSmrg                ret = FALSE;
175235c4bbdfSmrg        }
175335c4bbdfSmrg    }
175435c4bbdfSmrg
175535c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
175635c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
175735c4bbdfSmrg
175835c4bbdfSmrg        if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
175935c4bbdfSmrg            continue;
176035c4bbdfSmrg
176135c4bbdfSmrg        if (ret) {
176235c4bbdfSmrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
176335c4bbdfSmrg
176435c4bbdfSmrg            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
176535c4bbdfSmrg                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
176635c4bbdfSmrg        }
176735c4bbdfSmrg        else
176835c4bbdfSmrg            crtc->scanout_pixmap = saved_scanout_pixmap[i];
176935c4bbdfSmrg    }
177035c4bbdfSmrg    free(saved_scanout_pixmap);
177135c4bbdfSmrg
177235c4bbdfSmrg    return ret;
177335c4bbdfSmrg}
1774