rrcrtc.c revision 25da500f
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
281b5d61b8Smrg#include <X11/Xatom.h>
291b5d61b8Smrg
3035c4bbdfSmrgRESTYPE RRCrtcType;
3105b261ecSmrg
3205b261ecSmrg/*
3305b261ecSmrg * Notify the CRTC of some change
3405b261ecSmrg */
3505b261ecSmrgvoid
3635c4bbdfSmrgRRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged)
3705b261ecSmrg{
3835c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
3905b261ecSmrg
4005b261ecSmrg    crtc->changed = TRUE;
4135c4bbdfSmrg    if (pScreen) {
4235c4bbdfSmrg        rrScrPriv(pScreen);
4335c4bbdfSmrg
4435c4bbdfSmrg        RRSetChanged(pScreen);
4535c4bbdfSmrg        /*
4635c4bbdfSmrg         * Send ConfigureNotify on any layout change
4735c4bbdfSmrg         */
4835c4bbdfSmrg        if (layoutChanged)
4935c4bbdfSmrg            pScrPriv->layoutChanged = TRUE;
5005b261ecSmrg    }
5105b261ecSmrg}
5205b261ecSmrg
5305b261ecSmrg/*
5405b261ecSmrg * Create a CRTC
5505b261ecSmrg */
5605b261ecSmrgRRCrtcPtr
5735c4bbdfSmrgRRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
5805b261ecSmrg{
5935c4bbdfSmrg    RRCrtcPtr crtc;
6035c4bbdfSmrg    RRCrtcPtr *crtcs;
6135c4bbdfSmrg    rrScrPrivPtr pScrPriv;
6205b261ecSmrg
6305b261ecSmrg    if (!RRInit())
6435c4bbdfSmrg        return NULL;
6535c4bbdfSmrg
6605b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
6705b261ecSmrg
6805b261ecSmrg    /* make space for the crtc pointer */
691b5d61b8Smrg    crtcs = reallocarray(pScrPriv->crtcs,
701b5d61b8Smrg            pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr));
7105b261ecSmrg    if (!crtcs)
721b5d61b8Smrg        return NULL;
7305b261ecSmrg    pScrPriv->crtcs = crtcs;
7435c4bbdfSmrg
7535c4bbdfSmrg    crtc = calloc(1, sizeof(RRCrtcRec));
7605b261ecSmrg    if (!crtc)
7735c4bbdfSmrg        return NULL;
7835c4bbdfSmrg    crtc->id = FakeClientID(0);
7905b261ecSmrg    crtc->pScreen = pScreen;
8005b261ecSmrg    crtc->mode = NULL;
8105b261ecSmrg    crtc->x = 0;
8205b261ecSmrg    crtc->y = 0;
8305b261ecSmrg    crtc->rotation = RR_Rotate_0;
8405b261ecSmrg    crtc->rotations = RR_Rotate_0;
8505b261ecSmrg    crtc->outputs = NULL;
8605b261ecSmrg    crtc->numOutputs = 0;
8705b261ecSmrg    crtc->gammaSize = 0;
8805b261ecSmrg    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
8905b261ecSmrg    crtc->changed = FALSE;
9005b261ecSmrg    crtc->devPrivate = devPrivate;
9135c4bbdfSmrg    RRTransformInit(&crtc->client_pending_transform);
9235c4bbdfSmrg    RRTransformInit(&crtc->client_current_transform);
9335c4bbdfSmrg    pixman_transform_init_identity(&crtc->transform);
9435c4bbdfSmrg    pixman_f_transform_init_identity(&crtc->f_transform);
9535c4bbdfSmrg    pixman_f_transform_init_identity(&crtc->f_inverse);
9605b261ecSmrg
9735c4bbdfSmrg    if (!AddResource(crtc->id, RRCrtcType, (void *) crtc))
9835c4bbdfSmrg        return NULL;
9905b261ecSmrg
10005b261ecSmrg    /* attach the screen and crtc together */
10105b261ecSmrg    crtc->pScreen = pScreen;
10205b261ecSmrg    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
10335c4bbdfSmrg
10435c4bbdfSmrg    RRResourcesChanged(pScreen);
10535c4bbdfSmrg
10605b261ecSmrg    return crtc;
10705b261ecSmrg}
10805b261ecSmrg
10905b261ecSmrg/*
11005b261ecSmrg * Set the allowed rotations on a CRTC
11105b261ecSmrg */
11205b261ecSmrgvoid
11335c4bbdfSmrgRRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations)
11405b261ecSmrg{
11505b261ecSmrg    crtc->rotations = rotations;
11605b261ecSmrg}
11705b261ecSmrg
1184642e01fSmrg/*
1194642e01fSmrg * Set whether transforms are allowed on a CRTC
1204642e01fSmrg */
1214642e01fSmrgvoid
12235c4bbdfSmrgRRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
1234642e01fSmrg{
1244642e01fSmrg    crtc->transforms = transforms;
1254642e01fSmrg}
1264642e01fSmrg
12705b261ecSmrg/*
12805b261ecSmrg * Notify the extension that the Crtc has been reconfigured,
12905b261ecSmrg * the driver calls this whenever it has updated the mode
13005b261ecSmrg */
13105b261ecSmrgBool
13235c4bbdfSmrgRRCrtcNotify(RRCrtcPtr crtc,
13335c4bbdfSmrg             RRModePtr mode,
13435c4bbdfSmrg             int x,
13535c4bbdfSmrg             int y,
13635c4bbdfSmrg             Rotation rotation,
13735c4bbdfSmrg             RRTransformPtr transform, int numOutputs, RROutputPtr * outputs)
13805b261ecSmrg{
13935c4bbdfSmrg    int i, j;
14035c4bbdfSmrg
14105b261ecSmrg    /*
14205b261ecSmrg     * Check to see if any of the new outputs were
14305b261ecSmrg     * not in the old list and mark them as changed
14405b261ecSmrg     */
14535c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
14635c4bbdfSmrg        for (j = 0; j < crtc->numOutputs; j++)
14735c4bbdfSmrg            if (outputs[i] == crtc->outputs[j])
14835c4bbdfSmrg                break;
14935c4bbdfSmrg        if (j == crtc->numOutputs) {
15035c4bbdfSmrg            outputs[i]->crtc = crtc;
15135c4bbdfSmrg            RROutputChanged(outputs[i], FALSE);
15235c4bbdfSmrg            RRCrtcChanged(crtc, FALSE);
15335c4bbdfSmrg        }
15405b261ecSmrg    }
15505b261ecSmrg    /*
15605b261ecSmrg     * Check to see if any of the old outputs are
15705b261ecSmrg     * not in the new list and mark them as changed
15805b261ecSmrg     */
15935c4bbdfSmrg    for (j = 0; j < crtc->numOutputs; j++) {
16035c4bbdfSmrg        for (i = 0; i < numOutputs; i++)
16135c4bbdfSmrg            if (outputs[i] == crtc->outputs[j])
16235c4bbdfSmrg                break;
16335c4bbdfSmrg        if (i == numOutputs) {
16435c4bbdfSmrg            if (crtc->outputs[j]->crtc == crtc)
16535c4bbdfSmrg                crtc->outputs[j]->crtc = NULL;
16635c4bbdfSmrg            RROutputChanged(crtc->outputs[j], FALSE);
16735c4bbdfSmrg            RRCrtcChanged(crtc, FALSE);
16835c4bbdfSmrg        }
16905b261ecSmrg    }
17005b261ecSmrg    /*
17105b261ecSmrg     * Reallocate the crtc output array if necessary
17205b261ecSmrg     */
17335c4bbdfSmrg    if (numOutputs != crtc->numOutputs) {
17435c4bbdfSmrg        RROutputPtr *newoutputs;
17535c4bbdfSmrg
17635c4bbdfSmrg        if (numOutputs) {
17735c4bbdfSmrg            if (crtc->numOutputs)
17835c4bbdfSmrg                newoutputs = reallocarray(crtc->outputs,
17935c4bbdfSmrg                                          numOutputs, sizeof(RROutputPtr));
18035c4bbdfSmrg            else
18135c4bbdfSmrg                newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr));
18235c4bbdfSmrg            if (!newoutputs)
18335c4bbdfSmrg                return FALSE;
18435c4bbdfSmrg        }
18535c4bbdfSmrg        else {
18635c4bbdfSmrg            free(crtc->outputs);
18735c4bbdfSmrg            newoutputs = NULL;
18835c4bbdfSmrg        }
18935c4bbdfSmrg        crtc->outputs = newoutputs;
19035c4bbdfSmrg        crtc->numOutputs = numOutputs;
19105b261ecSmrg    }
19205b261ecSmrg    /*
19305b261ecSmrg     * Copy the new list of outputs into the crtc
19405b261ecSmrg     */
19535c4bbdfSmrg    memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr));
19605b261ecSmrg    /*
19705b261ecSmrg     * Update remaining crtc fields
19805b261ecSmrg     */
19935c4bbdfSmrg    if (mode != crtc->mode) {
20035c4bbdfSmrg        if (crtc->mode)
20135c4bbdfSmrg            RRModeDestroy(crtc->mode);
20235c4bbdfSmrg        crtc->mode = mode;
20335c4bbdfSmrg        if (mode != NULL)
20435c4bbdfSmrg            mode->refcnt++;
20535c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
20605b261ecSmrg    }
20735c4bbdfSmrg    if (x != crtc->x) {
20835c4bbdfSmrg        crtc->x = x;
20935c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
21005b261ecSmrg    }
21135c4bbdfSmrg    if (y != crtc->y) {
21235c4bbdfSmrg        crtc->y = y;
21335c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
21405b261ecSmrg    }
21535c4bbdfSmrg    if (rotation != crtc->rotation) {
21635c4bbdfSmrg        crtc->rotation = rotation;
21735c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
2184642e01fSmrg    }
21935c4bbdfSmrg    if (!RRTransformEqual(transform, &crtc->client_current_transform)) {
22035c4bbdfSmrg        RRTransformCopy(&crtc->client_current_transform, transform);
22135c4bbdfSmrg        RRCrtcChanged(crtc, TRUE);
22235c4bbdfSmrg    }
22335c4bbdfSmrg    if (crtc->changed && mode) {
22435c4bbdfSmrg        RRTransformCompute(x, y,
22535c4bbdfSmrg                           mode->mode.width, mode->mode.height,
22635c4bbdfSmrg                           rotation,
22735c4bbdfSmrg                           &crtc->client_current_transform,
22835c4bbdfSmrg                           &crtc->transform, &crtc->f_transform,
22935c4bbdfSmrg                           &crtc->f_inverse);
2304642e01fSmrg    }
23105b261ecSmrg    return TRUE;
23205b261ecSmrg}
23305b261ecSmrg
23405b261ecSmrgvoid
23535c4bbdfSmrgRRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
23605b261ecSmrg{
23705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
23835c4bbdfSmrg
23935c4bbdfSmrg    rrScrPriv(pScreen);
24035c4bbdfSmrg    RRModePtr mode = crtc->mode;
24135c4bbdfSmrg
24235c4bbdfSmrg    xRRCrtcChangeNotifyEvent ce = {
24335c4bbdfSmrg        .type = RRNotify + RREventBase,
24435c4bbdfSmrg        .subCode = RRNotify_CrtcChange,
24535c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
24635c4bbdfSmrg        .window = pWin->drawable.id,
24735c4bbdfSmrg        .crtc = crtc->id,
24835c4bbdfSmrg        .mode = mode ? mode->mode.id : None,
24935c4bbdfSmrg        .rotation = crtc->rotation,
25035c4bbdfSmrg        .x = mode ? crtc->x : 0,
25135c4bbdfSmrg        .y = mode ? crtc->y : 0,
25235c4bbdfSmrg        .width = mode ? mode->mode.width : 0,
25335c4bbdfSmrg        .height = mode ? mode->mode.height : 0
25435c4bbdfSmrg    };
25535c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &ce);
25635c4bbdfSmrg}
25735c4bbdfSmrg
25835c4bbdfSmrgstatic Bool
25935c4bbdfSmrgRRCrtcPendingProperties(RRCrtcPtr crtc)
26035c4bbdfSmrg{
26135c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
26235c4bbdfSmrg
26335c4bbdfSmrg    rrScrPriv(pScreen);
26435c4bbdfSmrg    int o;
26535c4bbdfSmrg
26635c4bbdfSmrg    for (o = 0; o < pScrPriv->numOutputs; o++) {
26735c4bbdfSmrg        RROutputPtr output = pScrPriv->outputs[o];
26835c4bbdfSmrg
26935c4bbdfSmrg        if (output->crtc == crtc && output->pendingProperties)
27035c4bbdfSmrg            return TRUE;
27105b261ecSmrg    }
27235c4bbdfSmrg    return FALSE;
27335c4bbdfSmrg}
27435c4bbdfSmrg
2751b5d61b8Smrgstatic Bool
2761b5d61b8Smrgcursor_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
27735c4bbdfSmrg{
2781b5d61b8Smrg    rrScrPriv(crtc->pScreen);
2791b5d61b8Smrg    BoxRec bounds;
28035c4bbdfSmrg
2811b5d61b8Smrg    if (crtc->mode == NULL)
2821b5d61b8Smrg	return FALSE;
2831b5d61b8Smrg
2841b5d61b8Smrg    memset(&bounds, 0, sizeof(bounds));
2851b5d61b8Smrg    if (pScrPriv->rrGetPanning)
2861b5d61b8Smrg	pScrPriv->rrGetPanning(crtc->pScreen, crtc, NULL, &bounds, NULL);
2871b5d61b8Smrg
2881b5d61b8Smrg    if (bounds.y2 <= bounds.y1 || bounds.x2 <= bounds.x1) {
2891b5d61b8Smrg	bounds.x1 = 0;
2901b5d61b8Smrg	bounds.y1 = 0;
2911b5d61b8Smrg	bounds.x2 = crtc->mode->mode.width;
2921b5d61b8Smrg	bounds.y2 = crtc->mode->mode.height;
29305b261ecSmrg    }
2941b5d61b8Smrg
2951b5d61b8Smrg    pixman_f_transform_bounds(&crtc->f_transform, &bounds);
2961b5d61b8Smrg
2971b5d61b8Smrg    *left = bounds.x1;
2981b5d61b8Smrg    *right = bounds.x2;
2991b5d61b8Smrg    *top = bounds.y1;
3001b5d61b8Smrg    *bottom = bounds.y2;
3011b5d61b8Smrg
3021b5d61b8Smrg    return TRUE;
30305b261ecSmrg}
30405b261ecSmrg
30535c4bbdfSmrg/* overlapping counts as adjacent */
30605b261ecSmrgstatic Bool
30735c4bbdfSmrgcrtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
30835c4bbdfSmrg{
30935c4bbdfSmrg    /* left, right, top, bottom... */
31035c4bbdfSmrg    int al, ar, at, ab;
31135c4bbdfSmrg    int bl, br, bt, bb;
31235c4bbdfSmrg    int cl, cr, ct, cb;         /* the overlap, if any */
31335c4bbdfSmrg
3141b5d61b8Smrg    if (!cursor_bounds(a, &al, &ar, &at, &ab))
3151b5d61b8Smrg	    return FALSE;
3161b5d61b8Smrg    if (!cursor_bounds(b, &bl, &br, &bt, &bb))
3171b5d61b8Smrg	    return FALSE;
31835c4bbdfSmrg
31935c4bbdfSmrg    cl = max(al, bl);
32035c4bbdfSmrg    cr = min(ar, br);
32135c4bbdfSmrg    ct = max(at, bt);
32235c4bbdfSmrg    cb = min(ab, bb);
32335c4bbdfSmrg
32435c4bbdfSmrg    return (cl <= cr) && (ct <= cb);
32535c4bbdfSmrg}
32635c4bbdfSmrg
32735c4bbdfSmrg/* Depth-first search and mark all CRTCs reachable from cur */
32835c4bbdfSmrgstatic void
32935c4bbdfSmrgmark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur)
33035c4bbdfSmrg{
33135c4bbdfSmrg    int i;
33235c4bbdfSmrg
33335c4bbdfSmrg    reachable[cur] = TRUE;
33435c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; ++i) {
3351b5d61b8Smrg        if (reachable[i])
33635c4bbdfSmrg            continue;
33735c4bbdfSmrg        if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
33835c4bbdfSmrg            mark_crtcs(pScrPriv, reachable, i);
33935c4bbdfSmrg    }
34035c4bbdfSmrg}
34135c4bbdfSmrg
34235c4bbdfSmrgstatic void
34335c4bbdfSmrgRRComputeContiguity(ScreenPtr pScreen)
34405b261ecSmrg{
34505b261ecSmrg    rrScrPriv(pScreen);
34635c4bbdfSmrg    Bool discontiguous = TRUE;
34735c4bbdfSmrg    int i, n = pScrPriv->numCrtcs;
34805b261ecSmrg
34935c4bbdfSmrg    int *reachable = calloc(n, sizeof(int));
35035c4bbdfSmrg
35135c4bbdfSmrg    if (!reachable)
35235c4bbdfSmrg        goto out;
35335c4bbdfSmrg
35435c4bbdfSmrg    /* Find first enabled CRTC and start search for reachable CRTCs from it */
35535c4bbdfSmrg    for (i = 0; i < n; ++i) {
35635c4bbdfSmrg        if (pScrPriv->crtcs[i]->mode) {
35735c4bbdfSmrg            mark_crtcs(pScrPriv, reachable, i);
35835c4bbdfSmrg            break;
35935c4bbdfSmrg        }
36005b261ecSmrg    }
36135c4bbdfSmrg
36235c4bbdfSmrg    /* Check that all enabled CRTCs were marked as reachable */
36335c4bbdfSmrg    for (i = 0; i < n; ++i)
36435c4bbdfSmrg        if (pScrPriv->crtcs[i]->mode && !reachable[i])
36535c4bbdfSmrg            goto out;
36635c4bbdfSmrg
36735c4bbdfSmrg    discontiguous = FALSE;
36835c4bbdfSmrg
36935c4bbdfSmrg out:
37035c4bbdfSmrg    free(reachable);
37135c4bbdfSmrg    pScrPriv->discontiguous = discontiguous;
37235c4bbdfSmrg}
37335c4bbdfSmrg
3741b5d61b8Smrgstatic void
3751b5d61b8SmrgrrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) {
37635c4bbdfSmrg    ScreenPtr master = crtc->pScreen->current_master;
37735c4bbdfSmrg
3781b5d61b8Smrg    if (master && pPixmap->master_pixmap) {
37935c4bbdfSmrg        /*
38035c4bbdfSmrg         * Unref the pixmap twice: once for the original reference, and once
38135c4bbdfSmrg         * for the reference implicitly added by PixmapShareToSlave.
38235c4bbdfSmrg         */
3831b5d61b8Smrg        PixmapUnshareSlavePixmap(pPixmap);
3841b5d61b8Smrg
3851b5d61b8Smrg        master->DestroyPixmap(pPixmap->master_pixmap);
3861b5d61b8Smrg        master->DestroyPixmap(pPixmap->master_pixmap);
38735c4bbdfSmrg    }
3881b5d61b8Smrg
3891b5d61b8Smrg    crtc->pScreen->DestroyPixmap(pPixmap);
39035c4bbdfSmrg}
39135c4bbdfSmrg
3921b5d61b8Smrgvoid
3931b5d61b8SmrgRRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
39435c4bbdfSmrg{
39535c4bbdfSmrg    rrScrPriv(crtc->pScreen);
39635c4bbdfSmrg
3971b5d61b8Smrg    if (crtc->scanout_pixmap) {
3981b5d61b8Smrg        ScreenPtr master = crtc->pScreen->current_master;
3991b5d61b8Smrg        DrawablePtr mrootdraw = &master->root->drawable;
40035c4bbdfSmrg
4011b5d61b8Smrg        if (crtc->scanout_pixmap_back) {
4021b5d61b8Smrg            pScrPriv->rrDisableSharedPixmapFlipping(crtc);
40335c4bbdfSmrg
40425da500fSmrg            if (mrootdraw) {
40525da500fSmrg                master->StopFlippingPixmapTracking(mrootdraw,
40625da500fSmrg                                                   crtc->scanout_pixmap,
40725da500fSmrg                                                   crtc->scanout_pixmap_back);
40825da500fSmrg            }
40935c4bbdfSmrg
4101b5d61b8Smrg            rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back);
4111b5d61b8Smrg            crtc->scanout_pixmap_back = NULL;
4121b5d61b8Smrg        }
4131b5d61b8Smrg        else {
4141b5d61b8Smrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
41525da500fSmrg
41625da500fSmrg            if (mrootdraw) {
41725da500fSmrg                master->StopPixmapTracking(mrootdraw,
41825da500fSmrg                                           crtc->scanout_pixmap);
41925da500fSmrg            }
4201b5d61b8Smrg        }
4211b5d61b8Smrg
4221b5d61b8Smrg        rrDestroySharedPixmap(crtc, crtc->scanout_pixmap);
4231b5d61b8Smrg        crtc->scanout_pixmap = NULL;
42435c4bbdfSmrg    }
42535c4bbdfSmrg
4261b5d61b8Smrg    RRCrtcChanged(crtc, TRUE);
4271b5d61b8Smrg}
4281b5d61b8Smrg
4291b5d61b8Smrgstatic PixmapPtr
4301b5d61b8SmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
4311b5d61b8Smrg                     int width, int height, int depth,
4321b5d61b8Smrg                     int x, int y, Rotation rotation)
4331b5d61b8Smrg{
4341b5d61b8Smrg    PixmapPtr mpix, spix;
4351b5d61b8Smrg
43635c4bbdfSmrg    mpix = master->CreatePixmap(master, width, height, depth,
43735c4bbdfSmrg                                CREATE_PIXMAP_USAGE_SHARED);
43835c4bbdfSmrg    if (!mpix)
4391b5d61b8Smrg        return NULL;
44035c4bbdfSmrg
44135c4bbdfSmrg    spix = PixmapShareToSlave(mpix, crtc->pScreen);
44235c4bbdfSmrg    if (spix == NULL) {
44335c4bbdfSmrg        master->DestroyPixmap(mpix);
4441b5d61b8Smrg        return NULL;
4451b5d61b8Smrg    }
4461b5d61b8Smrg
4471b5d61b8Smrg    return spix;
4481b5d61b8Smrg}
4491b5d61b8Smrg
4501b5d61b8Smrgstatic Bool
4511b5d61b8SmrgrrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs)
4521b5d61b8Smrg{
4531b5d61b8Smrg    /* Determine if the user wants prime syncing */
4541b5d61b8Smrg    int o;
4551b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
4561b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
4571b5d61b8Smrg    if (syncProp == None)
4581b5d61b8Smrg        return TRUE;
4591b5d61b8Smrg
4601b5d61b8Smrg    /* If one output doesn't want sync, no sync */
4611b5d61b8Smrg    for (o = 0; o < numOutputs; o++) {
4621b5d61b8Smrg        RRPropertyValuePtr val;
4631b5d61b8Smrg
4641b5d61b8Smrg        /* Try pending value first, then current value */
4651b5d61b8Smrg        if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) &&
4661b5d61b8Smrg            val->data) {
4671b5d61b8Smrg            if (!(*(char *) val->data))
4681b5d61b8Smrg                return FALSE;
4691b5d61b8Smrg            continue;
4701b5d61b8Smrg        }
4711b5d61b8Smrg
4721b5d61b8Smrg        if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) &&
4731b5d61b8Smrg            val->data) {
4741b5d61b8Smrg            if (!(*(char *) val->data))
4751b5d61b8Smrg                return FALSE;
4761b5d61b8Smrg            continue;
4771b5d61b8Smrg        }
4781b5d61b8Smrg    }
4791b5d61b8Smrg
4801b5d61b8Smrg    return TRUE;
4811b5d61b8Smrg}
4821b5d61b8Smrg
4831b5d61b8Smrgstatic void
4841b5d61b8SmrgrrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs)
4851b5d61b8Smrg{
4861b5d61b8Smrg    int o;
4871b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
4881b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
4891b5d61b8Smrg    if (syncProp == None)
4901b5d61b8Smrg        return;
4911b5d61b8Smrg
4921b5d61b8Smrg    for (o = 0; o < numOutputs; o++) {
4931b5d61b8Smrg        RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp);
4941b5d61b8Smrg        if (prop)
4951b5d61b8Smrg            RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER,
4961b5d61b8Smrg                                   8, PropModeReplace, 1, &val, FALSE, TRUE);
4971b5d61b8Smrg    }
4981b5d61b8Smrg}
4991b5d61b8Smrg
5001b5d61b8Smrgstatic Bool
5011b5d61b8SmrgrrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
5021b5d61b8Smrg                     int x, int y, Rotation rotation, Bool sync,
5031b5d61b8Smrg                     int numOutputs, RROutputPtr * outputs)
5041b5d61b8Smrg{
5051b5d61b8Smrg    ScreenPtr master = crtc->pScreen->current_master;
5061b5d61b8Smrg    rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master);
5071b5d61b8Smrg    rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen);
5081b5d61b8Smrg    DrawablePtr mrootdraw = &master->root->drawable;
5091b5d61b8Smrg    int depth = mrootdraw->depth;
5101b5d61b8Smrg    PixmapPtr spix_front;
5111b5d61b8Smrg
5121b5d61b8Smrg    /* Create a pixmap on the master screen, then get a shared handle for it.
5131b5d61b8Smrg       Create a shared pixmap on the slave screen using the handle.
5141b5d61b8Smrg
5151b5d61b8Smrg       If sync == FALSE --
5161b5d61b8Smrg       Set slave screen to scanout shared linear pixmap.
5171b5d61b8Smrg       Set the master screen to do dirty updates to the shared pixmap
5181b5d61b8Smrg       from the screen pixmap on its own accord.
5191b5d61b8Smrg
5201b5d61b8Smrg       If sync == TRUE --
5211b5d61b8Smrg       If any of the below steps fail, clean up and fall back to sync == FALSE.
5221b5d61b8Smrg       Create another shared pixmap on the slave screen using the handle.
5231b5d61b8Smrg       Set slave screen to prepare for scanout and flipping between shared
5241b5d61b8Smrg       linear pixmaps.
5251b5d61b8Smrg       Set the master screen to do dirty updates to the shared pixmaps from the
5261b5d61b8Smrg       screen pixmap when prompted to by us or the slave.
5271b5d61b8Smrg       Prompt the master to do a dirty update on the first shared pixmap, then
5281b5d61b8Smrg       defer to the slave.
5291b5d61b8Smrg    */
5301b5d61b8Smrg
5311b5d61b8Smrg    if (crtc->scanout_pixmap)
5321b5d61b8Smrg        RRCrtcDetachScanoutPixmap(crtc);
5331b5d61b8Smrg
5341b5d61b8Smrg    if (width == 0 && height == 0) {
5351b5d61b8Smrg        return TRUE;
5361b5d61b8Smrg    }
5371b5d61b8Smrg
5381b5d61b8Smrg    spix_front = rrCreateSharedPixmap(crtc, master,
5391b5d61b8Smrg                                      width, height, depth,
5401b5d61b8Smrg                                      x, y, rotation);
5411b5d61b8Smrg    if (spix_front == NULL) {
5421b5d61b8Smrg        ErrorF("randr: failed to create shared pixmap\n");
54335c4bbdfSmrg        return FALSE;
54435c4bbdfSmrg    }
54535c4bbdfSmrg
5461b5d61b8Smrg    /* Both source and sink must support required ABI funcs for flipping */
5471b5d61b8Smrg    if (sync &&
5481b5d61b8Smrg        pSlaveScrPriv->rrEnableSharedPixmapFlipping &&
5491b5d61b8Smrg        pSlaveScrPriv->rrDisableSharedPixmapFlipping &&
5501b5d61b8Smrg        pMasterScrPriv->rrStartFlippingPixmapTracking &&
5511b5d61b8Smrg        master->PresentSharedPixmap &&
5521b5d61b8Smrg        master->StopFlippingPixmapTracking) {
5531b5d61b8Smrg
5541b5d61b8Smrg        PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master,
5551b5d61b8Smrg                                                   width, height, depth,
5561b5d61b8Smrg                                                   x, y, rotation);
5571b5d61b8Smrg        if (spix_back == NULL)
5581b5d61b8Smrg            goto fail;
5591b5d61b8Smrg
5601b5d61b8Smrg        if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc,
5611b5d61b8Smrg                                                         spix_front, spix_back))
5621b5d61b8Smrg            goto fail;
5631b5d61b8Smrg
5641b5d61b8Smrg        crtc->scanout_pixmap = spix_front;
5651b5d61b8Smrg        crtc->scanout_pixmap_back = spix_back;
5661b5d61b8Smrg
5671b5d61b8Smrg        if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc,
5681b5d61b8Smrg                                                           mrootdraw,
5691b5d61b8Smrg                                                           spix_front,
5701b5d61b8Smrg                                                           spix_back,
5711b5d61b8Smrg                                                           x, y, 0, 0,
5721b5d61b8Smrg                                                           rotation)) {
5731b5d61b8Smrg            pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc);
5741b5d61b8Smrg            goto fail;
5751b5d61b8Smrg        }
5761b5d61b8Smrg
5771b5d61b8Smrg        master->PresentSharedPixmap(spix_front);
5781b5d61b8Smrg
5791b5d61b8Smrg        return TRUE;
5801b5d61b8Smrg
5811b5d61b8Smrgfail: /* If flipping funcs fail, just fall back to unsynchronized */
5821b5d61b8Smrg        if (spix_back)
5831b5d61b8Smrg            rrDestroySharedPixmap(crtc, spix_back);
5841b5d61b8Smrg
5851b5d61b8Smrg        crtc->scanout_pixmap = NULL;
5861b5d61b8Smrg        crtc->scanout_pixmap_back = NULL;
5871b5d61b8Smrg    }
5881b5d61b8Smrg
5891b5d61b8Smrg    if (sync) { /* Wanted sync, didn't get it */
5901b5d61b8Smrg        ErrorF("randr: falling back to unsynchronized pixmap sharing\n");
5911b5d61b8Smrg
5921b5d61b8Smrg        /* Set output property to 0 to indicate to user */
5931b5d61b8Smrg        rrSetPixmapSharingSyncProp(0, numOutputs, outputs);
5941b5d61b8Smrg    }
5951b5d61b8Smrg
5961b5d61b8Smrg    if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
5971b5d61b8Smrg        rrDestroySharedPixmap(crtc, spix_front);
59835c4bbdfSmrg        ErrorF("randr: failed to set shadow slave pixmap\n");
59935c4bbdfSmrg        return FALSE;
60035c4bbdfSmrg    }
6011b5d61b8Smrg    crtc->scanout_pixmap = spix_front;
60235c4bbdfSmrg
6031b5d61b8Smrg    master->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation);
60435c4bbdfSmrg
60535c4bbdfSmrg    return TRUE;
60635c4bbdfSmrg}
60735c4bbdfSmrg
60835c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
60935c4bbdfSmrg{
61035c4bbdfSmrg    box->x1 = crtc->x;
61135c4bbdfSmrg    box->y1 = crtc->y;
61235c4bbdfSmrg    switch (crtc->rotation) {
61335c4bbdfSmrg    case RR_Rotate_0:
61435c4bbdfSmrg    case RR_Rotate_180:
61535c4bbdfSmrg    default:
61635c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.width;
61735c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.height;
61835c4bbdfSmrg        break;
61935c4bbdfSmrg    case RR_Rotate_90:
62035c4bbdfSmrg    case RR_Rotate_270:
62135c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.height;
62235c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.width;
62335c4bbdfSmrg        break;
62435c4bbdfSmrg    }
62535c4bbdfSmrg}
62635c4bbdfSmrg
62735c4bbdfSmrgstatic Bool
62835c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen,
62935c4bbdfSmrg                      RRCrtcPtr rr_crtc, Rotation rotation,
63035c4bbdfSmrg                      int x, int y, int w, int h)
63135c4bbdfSmrg{
63235c4bbdfSmrg    RegionRec root_pixmap_region, total_region, new_crtc_region;
63335c4bbdfSmrg    int c;
63435c4bbdfSmrg    BoxRec newbox;
63535c4bbdfSmrg    BoxPtr newsize;
63635c4bbdfSmrg    ScreenPtr slave;
63735c4bbdfSmrg    int new_width, new_height;
63835c4bbdfSmrg    PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
63935c4bbdfSmrg    rrScrPriv(pScreen);
64035c4bbdfSmrg
64135c4bbdfSmrg    PixmapRegionInit(&root_pixmap_region, screen_pixmap);
64235c4bbdfSmrg    RegionInit(&total_region, NULL, 0);
64335c4bbdfSmrg
64435c4bbdfSmrg    /* have to iterate all the crtcs of the attached gpu masters
64535c4bbdfSmrg       and all their output slaves */
64635c4bbdfSmrg    for (c = 0; c < pScrPriv->numCrtcs; c++) {
64735c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[c];
64835c4bbdfSmrg
64935c4bbdfSmrg        if (crtc == rr_crtc) {
65035c4bbdfSmrg            newbox.x1 = x;
65135c4bbdfSmrg            newbox.y1 = y;
65235c4bbdfSmrg            if (rotation == RR_Rotate_90 ||
65335c4bbdfSmrg                rotation == RR_Rotate_270) {
65435c4bbdfSmrg                newbox.x2 = x + h;
65535c4bbdfSmrg                newbox.y2 = y + w;
65635c4bbdfSmrg            } else {
65735c4bbdfSmrg                newbox.x2 = x + w;
65835c4bbdfSmrg                newbox.y2 = y + h;
65935c4bbdfSmrg            }
66035c4bbdfSmrg        } else {
66135c4bbdfSmrg            if (!crtc->mode)
66235c4bbdfSmrg                continue;
66335c4bbdfSmrg            crtc_to_box(&newbox, crtc);
66435c4bbdfSmrg        }
66535c4bbdfSmrg        RegionInit(&new_crtc_region, &newbox, 1);
66635c4bbdfSmrg        RegionUnion(&total_region, &total_region, &new_crtc_region);
66735c4bbdfSmrg    }
66835c4bbdfSmrg
6691b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
67035c4bbdfSmrg        rrScrPrivPtr    slave_priv = rrGetScrPriv(slave);
6711b5d61b8Smrg
6721b5d61b8Smrg        if (!slave->is_output_slave)
6731b5d61b8Smrg            continue;
6741b5d61b8Smrg
67535c4bbdfSmrg        for (c = 0; c < slave_priv->numCrtcs; c++) {
67635c4bbdfSmrg            RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
67735c4bbdfSmrg
67835c4bbdfSmrg            if (slave_crtc == rr_crtc) {
67935c4bbdfSmrg                newbox.x1 = x;
68035c4bbdfSmrg                newbox.y1 = y;
68135c4bbdfSmrg                if (rotation == RR_Rotate_90 ||
68235c4bbdfSmrg                    rotation == RR_Rotate_270) {
68335c4bbdfSmrg                    newbox.x2 = x + h;
68435c4bbdfSmrg                    newbox.y2 = y + w;
68535c4bbdfSmrg                } else {
68635c4bbdfSmrg                    newbox.x2 = x + w;
68735c4bbdfSmrg                    newbox.y2 = y + h;
68835c4bbdfSmrg                }
68935c4bbdfSmrg            }
69035c4bbdfSmrg            else {
69135c4bbdfSmrg                if (!slave_crtc->mode)
69235c4bbdfSmrg                    continue;
69335c4bbdfSmrg                crtc_to_box(&newbox, slave_crtc);
69435c4bbdfSmrg            }
69535c4bbdfSmrg            RegionInit(&new_crtc_region, &newbox, 1);
69635c4bbdfSmrg            RegionUnion(&total_region, &total_region, &new_crtc_region);
69735c4bbdfSmrg        }
69835c4bbdfSmrg    }
69935c4bbdfSmrg
70035c4bbdfSmrg    newsize = RegionExtents(&total_region);
7011b5d61b8Smrg    new_width = newsize->x2;
7021b5d61b8Smrg    new_height = newsize->y2;
7031b5d61b8Smrg
7041b5d61b8Smrg    if (new_width < screen_pixmap->drawable.width)
7051b5d61b8Smrg        new_width = screen_pixmap->drawable.width;
70635c4bbdfSmrg
7071b5d61b8Smrg    if (new_height < screen_pixmap->drawable.height)
7081b5d61b8Smrg        new_height = screen_pixmap->drawable.height;
7091b5d61b8Smrg
7101b5d61b8Smrg    if (new_width <= screen_pixmap->drawable.width &&
7111b5d61b8Smrg        new_height <= screen_pixmap->drawable.height) {
71235c4bbdfSmrg    } else {
71335c4bbdfSmrg        pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
71435c4bbdfSmrg    }
71535c4bbdfSmrg
71635c4bbdfSmrg    /* set shatters TODO */
71735c4bbdfSmrg    return TRUE;
71805b261ecSmrg}
71905b261ecSmrg
72005b261ecSmrg/*
72105b261ecSmrg * Request that the Crtc be reconfigured
72205b261ecSmrg */
72305b261ecSmrgBool
72435c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc,
72535c4bbdfSmrg          RRModePtr mode,
72635c4bbdfSmrg          int x,
72735c4bbdfSmrg          int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
72805b261ecSmrg{
72935c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
73035c4bbdfSmrg    Bool ret = FALSE;
73135c4bbdfSmrg    Bool recompute = TRUE;
73235c4bbdfSmrg    Bool crtcChanged;
73335c4bbdfSmrg    int  o;
73435c4bbdfSmrg
73505b261ecSmrg    rrScrPriv(pScreen);
73605b261ecSmrg
73735c4bbdfSmrg    crtcChanged = FALSE;
73835c4bbdfSmrg    for (o = 0; o < numOutputs; o++) {
73935c4bbdfSmrg        if (outputs[o] && outputs[o]->crtc != crtc) {
74035c4bbdfSmrg            crtcChanged = TRUE;
74135c4bbdfSmrg            break;
74235c4bbdfSmrg        }
74335c4bbdfSmrg    }
74435c4bbdfSmrg
74505b261ecSmrg    /* See if nothing changed */
74605b261ecSmrg    if (crtc->mode == mode &&
74735c4bbdfSmrg        crtc->x == x &&
74835c4bbdfSmrg        crtc->y == y &&
74935c4bbdfSmrg        crtc->rotation == rotation &&
75035c4bbdfSmrg        crtc->numOutputs == numOutputs &&
75135c4bbdfSmrg        !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
75235c4bbdfSmrg        !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
75335c4bbdfSmrg        !crtcChanged) {
75435c4bbdfSmrg        recompute = FALSE;
75535c4bbdfSmrg        ret = TRUE;
75605b261ecSmrg    }
75735c4bbdfSmrg    else {
75835c4bbdfSmrg        if (pScreen->isGPU) {
75935c4bbdfSmrg            ScreenPtr master = pScreen->current_master;
76035c4bbdfSmrg            int width = 0, height = 0;
76135c4bbdfSmrg
76235c4bbdfSmrg            if (mode) {
76335c4bbdfSmrg                width = mode->mode.width;
76435c4bbdfSmrg                height = mode->mode.height;
76535c4bbdfSmrg            }
76635c4bbdfSmrg            ret = rrCheckPixmapBounding(master, crtc,
76735c4bbdfSmrg                                        rotation, x, y, width, height);
76835c4bbdfSmrg            if (!ret)
76935c4bbdfSmrg                return FALSE;
77035c4bbdfSmrg
77135c4bbdfSmrg            if (pScreen->current_master) {
7721b5d61b8Smrg                Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs);
7731b5d61b8Smrg                ret = rrSetupPixmapSharing(crtc, width, height,
7741b5d61b8Smrg                                           x, y, rotation, sync,
7751b5d61b8Smrg                                           numOutputs, outputs);
77635c4bbdfSmrg            }
77735c4bbdfSmrg        }
77805b261ecSmrg#if RANDR_12_INTERFACE
77935c4bbdfSmrg        if (pScrPriv->rrCrtcSet) {
78035c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
78135c4bbdfSmrg                                          rotation, numOutputs, outputs);
78235c4bbdfSmrg        }
78335c4bbdfSmrg        else
78405b261ecSmrg#endif
78535c4bbdfSmrg        {
78605b261ecSmrg#if RANDR_10_INTERFACE
78735c4bbdfSmrg            if (pScrPriv->rrSetConfig) {
78835c4bbdfSmrg                RRScreenSize size;
78935c4bbdfSmrg                RRScreenRate rate;
79035c4bbdfSmrg
79135c4bbdfSmrg                if (!mode) {
79235c4bbdfSmrg                    RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
79335c4bbdfSmrg                    ret = TRUE;
79435c4bbdfSmrg                }
79535c4bbdfSmrg                else {
79635c4bbdfSmrg                    size.width = mode->mode.width;
79735c4bbdfSmrg                    size.height = mode->mode.height;
79835c4bbdfSmrg                    if (outputs[0]->mmWidth && outputs[0]->mmHeight) {
79935c4bbdfSmrg                        size.mmWidth = outputs[0]->mmWidth;
80035c4bbdfSmrg                        size.mmHeight = outputs[0]->mmHeight;
80135c4bbdfSmrg                    }
80235c4bbdfSmrg                    else {
80335c4bbdfSmrg                        size.mmWidth = pScreen->mmWidth;
80435c4bbdfSmrg                        size.mmHeight = pScreen->mmHeight;
80535c4bbdfSmrg                    }
80635c4bbdfSmrg                    size.nRates = 1;
80735c4bbdfSmrg                    rate.rate = RRVerticalRefresh(&mode->mode);
80835c4bbdfSmrg                    size.pRates = &rate;
80935c4bbdfSmrg                    ret =
81035c4bbdfSmrg                        (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate,
81135c4bbdfSmrg                                                  &size);
81235c4bbdfSmrg                    /*
81335c4bbdfSmrg                     * Old 1.0 interface tied screen size to mode size
81435c4bbdfSmrg                     */
81535c4bbdfSmrg                    if (ret) {
81635c4bbdfSmrg                        RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
81735c4bbdfSmrg                                     outputs);
81835c4bbdfSmrg                        RRScreenSizeNotify(pScreen);
81935c4bbdfSmrg                    }
82035c4bbdfSmrg                }
82135c4bbdfSmrg            }
82205b261ecSmrg#endif
82335c4bbdfSmrg        }
82435c4bbdfSmrg        if (ret) {
82505b261ecSmrg
82635c4bbdfSmrg            RRTellChanged(pScreen);
82735c4bbdfSmrg
82835c4bbdfSmrg            for (o = 0; o < numOutputs; o++)
82935c4bbdfSmrg                RRPostPendingProperties(outputs[o]);
83035c4bbdfSmrg        }
83105b261ecSmrg    }
83235c4bbdfSmrg
83335c4bbdfSmrg    if (recompute)
83435c4bbdfSmrg        RRComputeContiguity(pScreen);
83535c4bbdfSmrg
83605b261ecSmrg    return ret;
83705b261ecSmrg}
83805b261ecSmrg
8394642e01fSmrg/*
8404642e01fSmrg * Return crtc transform
8414642e01fSmrg */
8424642e01fSmrgRRTransformPtr
84335c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc)
8444642e01fSmrg{
84535c4bbdfSmrg    RRTransformPtr transform = &crtc->client_pending_transform;
8464642e01fSmrg
84735c4bbdfSmrg    if (pixman_transform_is_identity(&transform->transform))
84835c4bbdfSmrg        return NULL;
8494642e01fSmrg    return transform;
8504642e01fSmrg}
8514642e01fSmrg
8524642e01fSmrg/*
8534642e01fSmrg * Check whether the pending and current transforms are the same
8544642e01fSmrg */
8554642e01fSmrgBool
85635c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc)
8574642e01fSmrg{
8581b5d61b8Smrg    return !RRTransformEqual(&crtc->client_current_transform,
8591b5d61b8Smrg                             &crtc->client_pending_transform);
8604642e01fSmrg}
8614642e01fSmrg
86205b261ecSmrg/*
86305b261ecSmrg * Destroy a Crtc at shutdown
86405b261ecSmrg */
86505b261ecSmrgvoid
86635c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc)
86705b261ecSmrg{
86835c4bbdfSmrg    FreeResource(crtc->id, 0);
86905b261ecSmrg}
87005b261ecSmrg
87105b261ecSmrgstatic int
87235c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid)
87305b261ecSmrg{
87435c4bbdfSmrg    RRCrtcPtr crtc = (RRCrtcPtr) value;
87535c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
87605b261ecSmrg
87735c4bbdfSmrg    if (pScreen) {
87835c4bbdfSmrg        rrScrPriv(pScreen);
87935c4bbdfSmrg        int i;
8801b5d61b8Smrg        RRLeasePtr lease, next;
8811b5d61b8Smrg
8821b5d61b8Smrg        xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) {
8831b5d61b8Smrg            int c;
8841b5d61b8Smrg            for (c = 0; c < lease->numCrtcs; c++) {
8851b5d61b8Smrg                if (lease->crtcs[c] == crtc) {
8861b5d61b8Smrg                    RRTerminateLease(lease);
8871b5d61b8Smrg                    break;
8881b5d61b8Smrg                }
8891b5d61b8Smrg            }
8901b5d61b8Smrg        }
89135c4bbdfSmrg
89235c4bbdfSmrg        for (i = 0; i < pScrPriv->numCrtcs; i++) {
89335c4bbdfSmrg            if (pScrPriv->crtcs[i] == crtc) {
89435c4bbdfSmrg                memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
89535c4bbdfSmrg                        (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr));
89635c4bbdfSmrg                --pScrPriv->numCrtcs;
89735c4bbdfSmrg                break;
89835c4bbdfSmrg            }
89935c4bbdfSmrg        }
90035c4bbdfSmrg
90135c4bbdfSmrg        RRResourcesChanged(pScreen);
90205b261ecSmrg    }
90335c4bbdfSmrg
90435c4bbdfSmrg    if (crtc->scanout_pixmap)
90535c4bbdfSmrg        RRCrtcDetachScanoutPixmap(crtc);
9066747b715Smrg    free(crtc->gammaRed);
90705b261ecSmrg    if (crtc->mode)
90835c4bbdfSmrg        RRModeDestroy(crtc->mode);
9091b5d61b8Smrg    free(crtc->outputs);
9106747b715Smrg    free(crtc);
91105b261ecSmrg    return 1;
91205b261ecSmrg}
91305b261ecSmrg
91405b261ecSmrg/*
91505b261ecSmrg * Request that the Crtc gamma be changed
91605b261ecSmrg */
91705b261ecSmrg
91805b261ecSmrgBool
91935c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
92005b261ecSmrg{
92135c4bbdfSmrg    Bool ret = TRUE;
92235c4bbdfSmrg
92305b261ecSmrg#if RANDR_12_INTERFACE
92435c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
92505b261ecSmrg#endif
92635c4bbdfSmrg
92735c4bbdfSmrg    memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16));
92835c4bbdfSmrg    memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16));
92935c4bbdfSmrg    memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16));
93005b261ecSmrg#if RANDR_12_INTERFACE
93135c4bbdfSmrg    if (pScreen) {
93235c4bbdfSmrg        rrScrPriv(pScreen);
93335c4bbdfSmrg        if (pScrPriv->rrCrtcSetGamma)
93435c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
93505b261ecSmrg    }
93605b261ecSmrg#endif
93705b261ecSmrg    return ret;
93805b261ecSmrg}
93905b261ecSmrg
9406747b715Smrg/*
9416747b715Smrg * Request current gamma back from the DDX (if possible).
9426747b715Smrg * This includes gamma size.
9436747b715Smrg */
9446747b715SmrgBool
9456747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc)
9466747b715Smrg{
9476747b715Smrg    Bool ret = TRUE;
94835c4bbdfSmrg
9496747b715Smrg#if RANDR_12_INTERFACE
95035c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
9516747b715Smrg#endif
9526747b715Smrg
9536747b715Smrg#if RANDR_12_INTERFACE
95435c4bbdfSmrg    if (pScreen) {
9556747b715Smrg        rrScrPriv(pScreen);
9566747b715Smrg        if (pScrPriv->rrCrtcGetGamma)
9576747b715Smrg            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
9586747b715Smrg    }
9596747b715Smrg#endif
9606747b715Smrg    return ret;
9616747b715Smrg}
9626747b715Smrg
96305b261ecSmrg/*
96405b261ecSmrg * Notify the extension that the Crtc gamma has been changed
96505b261ecSmrg * The driver calls this whenever it has changed the gamma values
96605b261ecSmrg * in the RRCrtcRec
96705b261ecSmrg */
96805b261ecSmrg
96905b261ecSmrgBool
97035c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc)
97105b261ecSmrg{
97235c4bbdfSmrg    return TRUE;                /* not much going on here */
97305b261ecSmrg}
97405b261ecSmrg
9754642e01fSmrgstatic void
97635c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
97735c4bbdfSmrg                     int *width, int *height)
97805b261ecSmrg{
97935c4bbdfSmrg    BoxRec box;
9804642e01fSmrg
9814642e01fSmrg    if (mode == NULL) {
98235c4bbdfSmrg        *width = 0;
98335c4bbdfSmrg        *height = 0;
98435c4bbdfSmrg        return;
98505b261ecSmrg    }
98605b261ecSmrg
9874642e01fSmrg    box.x1 = 0;
9884642e01fSmrg    box.y1 = 0;
9894642e01fSmrg    box.x2 = mode->mode.width;
9904642e01fSmrg    box.y2 = mode->mode.height;
9914642e01fSmrg
99235c4bbdfSmrg    pixman_transform_bounds(transform, &box);
9934642e01fSmrg    *width = box.x2 - box.x1;
9944642e01fSmrg    *height = box.y2 - box.y1;
9954642e01fSmrg}
9964642e01fSmrg
9974642e01fSmrg/**
9984642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer
9994642e01fSmrg */
10004642e01fSmrgvoid
10014642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
10024642e01fSmrg{
100335c4bbdfSmrg    RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
100405b261ecSmrg}
100505b261ecSmrg
100605b261ecSmrg/*
100705b261ecSmrg * Set the size of the gamma table at server startup time
100805b261ecSmrg */
100905b261ecSmrg
101005b261ecSmrgBool
101135c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
101205b261ecSmrg{
101335c4bbdfSmrg    CARD16 *gamma;
101405b261ecSmrg
101505b261ecSmrg    if (size == crtc->gammaSize)
101635c4bbdfSmrg        return TRUE;
101735c4bbdfSmrg    if (size) {
101835c4bbdfSmrg        gamma = xallocarray(size, 3 * sizeof(CARD16));
101935c4bbdfSmrg        if (!gamma)
102035c4bbdfSmrg            return FALSE;
102105b261ecSmrg    }
102205b261ecSmrg    else
102335c4bbdfSmrg        gamma = NULL;
10246747b715Smrg    free(crtc->gammaRed);
102505b261ecSmrg    crtc->gammaRed = gamma;
102605b261ecSmrg    crtc->gammaGreen = gamma + size;
102735c4bbdfSmrg    crtc->gammaBlue = gamma + size * 2;
102805b261ecSmrg    crtc->gammaSize = size;
102905b261ecSmrg    return TRUE;
103005b261ecSmrg}
103105b261ecSmrg
10324642e01fSmrg/*
10334642e01fSmrg * Set the pending CRTC transformation
10344642e01fSmrg */
10354642e01fSmrg
10364642e01fSmrgint
103735c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc,
103835c4bbdfSmrg                   PictTransformPtr transform,
103935c4bbdfSmrg                   struct pixman_f_transform *f_transform,
104035c4bbdfSmrg                   struct pixman_f_transform *f_inverse,
104135c4bbdfSmrg                   char *filter_name,
104235c4bbdfSmrg                   int filter_len, xFixed * params, int nparams)
10434642e01fSmrg{
104435c4bbdfSmrg    PictFilterPtr filter = NULL;
104535c4bbdfSmrg    int width = 0, height = 0;
10464642e01fSmrg
10474642e01fSmrg    if (!crtc->transforms)
104835c4bbdfSmrg        return BadValue;
104935c4bbdfSmrg
105035c4bbdfSmrg    if (filter_len) {
105135c4bbdfSmrg        filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
105235c4bbdfSmrg        if (!filter)
105335c4bbdfSmrg            return BadName;
105435c4bbdfSmrg        if (filter->ValidateParams) {
105535c4bbdfSmrg            if (!filter->ValidateParams(crtc->pScreen, filter->id,
105635c4bbdfSmrg                                        params, nparams, &width, &height))
105735c4bbdfSmrg                return BadMatch;
105835c4bbdfSmrg        }
105935c4bbdfSmrg        else {
106035c4bbdfSmrg            width = filter->width;
106135c4bbdfSmrg            height = filter->height;
106235c4bbdfSmrg        }
10634642e01fSmrg    }
106435c4bbdfSmrg    else {
106535c4bbdfSmrg        if (nparams)
106635c4bbdfSmrg            return BadMatch;
10674642e01fSmrg    }
106835c4bbdfSmrg    if (!RRTransformSetFilter(&crtc->client_pending_transform,
106935c4bbdfSmrg                              filter, params, nparams, width, height))
107035c4bbdfSmrg        return BadAlloc;
10714642e01fSmrg
10724642e01fSmrg    crtc->client_pending_transform.transform = *transform;
10734642e01fSmrg    crtc->client_pending_transform.f_transform = *f_transform;
10744642e01fSmrg    crtc->client_pending_transform.f_inverse = *f_inverse;
10754642e01fSmrg    return Success;
10764642e01fSmrg}
10774642e01fSmrg
107805b261ecSmrg/*
107905b261ecSmrg * Initialize crtc type
108005b261ecSmrg */
108105b261ecSmrgBool
108235c4bbdfSmrgRRCrtcInit(void)
108305b261ecSmrg{
108435c4bbdfSmrg    RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
108505b261ecSmrg    if (!RRCrtcType)
108635c4bbdfSmrg        return FALSE;
108735c4bbdfSmrg
108805b261ecSmrg    return TRUE;
108905b261ecSmrg}
109005b261ecSmrg
10916747b715Smrg/*
10926747b715Smrg * Initialize crtc type error value
10936747b715Smrg */
10946747b715Smrgvoid
10956747b715SmrgRRCrtcInitErrorValue(void)
10966747b715Smrg{
10976747b715Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
10986747b715Smrg}
10996747b715Smrg
110005b261ecSmrgint
110135c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client)
110205b261ecSmrg{
110305b261ecSmrg    REQUEST(xRRGetCrtcInfoReq);
110435c4bbdfSmrg    xRRGetCrtcInfoReply rep;
110535c4bbdfSmrg    RRCrtcPtr crtc;
11061b5d61b8Smrg    CARD8 *extra = NULL;
110735c4bbdfSmrg    unsigned long extraLen;
110835c4bbdfSmrg    ScreenPtr pScreen;
110935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
111035c4bbdfSmrg    RRModePtr mode;
111135c4bbdfSmrg    RROutput *outputs;
111235c4bbdfSmrg    RROutput *possible;
111335c4bbdfSmrg    int i, j, k;
111435c4bbdfSmrg    int width, height;
111535c4bbdfSmrg    BoxRec panned_area;
11161b5d61b8Smrg    Bool leased;
111735c4bbdfSmrg
111805b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
11196747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
112005b261ecSmrg
11211b5d61b8Smrg    leased = RRCrtcIsLeased(crtc);
11221b5d61b8Smrg
112305b261ecSmrg    /* All crtcs must be associated with screens before client
112405b261ecSmrg     * requests are processed
112505b261ecSmrg     */
112605b261ecSmrg    pScreen = crtc->pScreen;
112705b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
112805b261ecSmrg
112905b261ecSmrg    mode = crtc->mode;
113035c4bbdfSmrg
113135c4bbdfSmrg    rep = (xRRGetCrtcInfoReply) {
113235c4bbdfSmrg        .type = X_Reply,
113335c4bbdfSmrg        .status = RRSetConfigSuccess,
113435c4bbdfSmrg        .sequenceNumber = client->sequence,
113535c4bbdfSmrg        .length = 0,
113635c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
113735c4bbdfSmrg    };
11381b5d61b8Smrg    if (leased) {
11391b5d61b8Smrg        rep.x = rep.y = rep.width = rep.height = 0;
11401b5d61b8Smrg        rep.mode = 0;
11411b5d61b8Smrg        rep.rotation = RR_Rotate_0;
11421b5d61b8Smrg        rep.rotations = RR_Rotate_0;
11431b5d61b8Smrg        rep.nOutput = 0;
11441b5d61b8Smrg        rep.nPossibleOutput = 0;
11451b5d61b8Smrg        rep.length = 0;
11461b5d61b8Smrg        extraLen = 0;
11471b5d61b8Smrg    } else {
11481b5d61b8Smrg        if (pScrPriv->rrGetPanning &&
11491b5d61b8Smrg            pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
11501b5d61b8Smrg            (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
11511b5d61b8Smrg        {
11521b5d61b8Smrg            rep.x = panned_area.x1;
11531b5d61b8Smrg            rep.y = panned_area.y1;
11541b5d61b8Smrg            rep.width = panned_area.x2 - panned_area.x1;
11551b5d61b8Smrg            rep.height = panned_area.y2 - panned_area.y1;
11561b5d61b8Smrg        }
11571b5d61b8Smrg        else {
11581b5d61b8Smrg            RRCrtcGetScanoutSize(crtc, &width, &height);
11591b5d61b8Smrg            rep.x = crtc->x;
11601b5d61b8Smrg            rep.y = crtc->y;
11611b5d61b8Smrg            rep.width = width;
11621b5d61b8Smrg            rep.height = height;
11631b5d61b8Smrg        }
11641b5d61b8Smrg        rep.mode = mode ? mode->mode.id : 0;
11651b5d61b8Smrg        rep.rotation = crtc->rotation;
11661b5d61b8Smrg        rep.rotations = crtc->rotations;
11671b5d61b8Smrg        rep.nOutput = crtc->numOutputs;
11681b5d61b8Smrg        k = 0;
11691b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
11701b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
11711b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
11721b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
11731b5d61b8Smrg                        k++;
117435c4bbdfSmrg            }
11751b5d61b8Smrg        }
11761b5d61b8Smrg
11771b5d61b8Smrg        rep.nPossibleOutput = k;
11781b5d61b8Smrg
11791b5d61b8Smrg        rep.length = rep.nOutput + rep.nPossibleOutput;
11801b5d61b8Smrg
11811b5d61b8Smrg        extraLen = rep.length << 2;
11821b5d61b8Smrg        if (extraLen) {
11831b5d61b8Smrg            extra = malloc(extraLen);
11841b5d61b8Smrg            if (!extra)
11851b5d61b8Smrg                return BadAlloc;
11861b5d61b8Smrg        }
11871b5d61b8Smrg
11881b5d61b8Smrg        outputs = (RROutput *) extra;
11891b5d61b8Smrg        possible = (RROutput *) (outputs + rep.nOutput);
11901b5d61b8Smrg
11911b5d61b8Smrg        for (i = 0; i < crtc->numOutputs; i++) {
11921b5d61b8Smrg            outputs[i] = crtc->outputs[i]->id;
11931b5d61b8Smrg            if (client->swapped)
11941b5d61b8Smrg                swapl(&outputs[i]);
11951b5d61b8Smrg        }
11961b5d61b8Smrg        k = 0;
11971b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
11981b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
11991b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
12001b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
12011b5d61b8Smrg                        possible[k] = pScrPriv->outputs[i]->id;
12021b5d61b8Smrg                        if (client->swapped)
12031b5d61b8Smrg                            swapl(&possible[k]);
12041b5d61b8Smrg                        k++;
12051b5d61b8Smrg                    }
12061b5d61b8Smrg            }
12071b5d61b8Smrg        }
12081b5d61b8Smrg    }
120935c4bbdfSmrg
121005b261ecSmrg    if (client->swapped) {
121135c4bbdfSmrg        swaps(&rep.sequenceNumber);
121235c4bbdfSmrg        swapl(&rep.length);
121335c4bbdfSmrg        swapl(&rep.timestamp);
121435c4bbdfSmrg        swaps(&rep.x);
121535c4bbdfSmrg        swaps(&rep.y);
121635c4bbdfSmrg        swaps(&rep.width);
121735c4bbdfSmrg        swaps(&rep.height);
121835c4bbdfSmrg        swapl(&rep.mode);
121935c4bbdfSmrg        swaps(&rep.rotation);
122035c4bbdfSmrg        swaps(&rep.rotations);
122135c4bbdfSmrg        swaps(&rep.nOutput);
122235c4bbdfSmrg        swaps(&rep.nPossibleOutput);
122335c4bbdfSmrg    }
122435c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
122535c4bbdfSmrg    if (extraLen) {
122635c4bbdfSmrg        WriteToClient(client, extraLen, extra);
122735c4bbdfSmrg        free(extra);
122805b261ecSmrg    }
122935c4bbdfSmrg
12306747b715Smrg    return Success;
123105b261ecSmrg}
123205b261ecSmrg
123305b261ecSmrgint
123435c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client)
123505b261ecSmrg{
123605b261ecSmrg    REQUEST(xRRSetCrtcConfigReq);
123735c4bbdfSmrg    xRRSetCrtcConfigReply rep;
123835c4bbdfSmrg    ScreenPtr pScreen;
123935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
124035c4bbdfSmrg    RRCrtcPtr crtc;
124135c4bbdfSmrg    RRModePtr mode;
124235c4bbdfSmrg    int numOutputs;
124335c4bbdfSmrg    RROutputPtr *outputs = NULL;
124435c4bbdfSmrg    RROutput *outputIds;
124535c4bbdfSmrg    TimeStamp time;
124635c4bbdfSmrg    Rotation rotation;
124735c4bbdfSmrg    int ret, i, j;
124835c4bbdfSmrg    CARD8 status;
124935c4bbdfSmrg
125005b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
125135c4bbdfSmrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
125235c4bbdfSmrg
12536747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
12546747b715Smrg
12551b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
12561b5d61b8Smrg        return BadAccess;
12571b5d61b8Smrg
125835c4bbdfSmrg    if (stuff->mode == None) {
125935c4bbdfSmrg        mode = NULL;
126035c4bbdfSmrg        if (numOutputs > 0)
126135c4bbdfSmrg            return BadMatch;
126205b261ecSmrg    }
126335c4bbdfSmrg    else {
126435c4bbdfSmrg        VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
126535c4bbdfSmrg        if (numOutputs == 0)
126635c4bbdfSmrg            return BadMatch;
126705b261ecSmrg    }
126835c4bbdfSmrg    if (numOutputs) {
126935c4bbdfSmrg        outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
127035c4bbdfSmrg        if (!outputs)
127135c4bbdfSmrg            return BadAlloc;
127205b261ecSmrg    }
127305b261ecSmrg    else
127435c4bbdfSmrg        outputs = NULL;
127535c4bbdfSmrg
127605b261ecSmrg    outputIds = (RROutput *) (stuff + 1);
127735c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
127835c4bbdfSmrg        ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
127935c4bbdfSmrg                                     RROutputType, client, DixSetAttrAccess);
128035c4bbdfSmrg        if (ret != Success) {
128135c4bbdfSmrg            free(outputs);
128235c4bbdfSmrg            return ret;
128335c4bbdfSmrg        }
12841b5d61b8Smrg
12851b5d61b8Smrg        if (RROutputIsLeased(outputs[i])) {
12861b5d61b8Smrg            free(outputs);
12871b5d61b8Smrg            return BadAccess;
12881b5d61b8Smrg        }
12891b5d61b8Smrg
129035c4bbdfSmrg        /* validate crtc for this output */
129135c4bbdfSmrg        for (j = 0; j < outputs[i]->numCrtcs; j++)
129235c4bbdfSmrg            if (outputs[i]->crtcs[j] == crtc)
129335c4bbdfSmrg                break;
129435c4bbdfSmrg        if (j == outputs[i]->numCrtcs) {
129535c4bbdfSmrg            free(outputs);
129635c4bbdfSmrg            return BadMatch;
129735c4bbdfSmrg        }
129835c4bbdfSmrg        /* validate mode for this output */
129935c4bbdfSmrg        for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
130035c4bbdfSmrg            RRModePtr m = (j < outputs[i]->numModes ?
130135c4bbdfSmrg                           outputs[i]->modes[j] :
130235c4bbdfSmrg                           outputs[i]->userModes[j - outputs[i]->numModes]);
130335c4bbdfSmrg            if (m == mode)
130435c4bbdfSmrg                break;
130535c4bbdfSmrg        }
130635c4bbdfSmrg        if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
130735c4bbdfSmrg            free(outputs);
130835c4bbdfSmrg            return BadMatch;
130935c4bbdfSmrg        }
131005b261ecSmrg    }
131105b261ecSmrg    /* validate clones */
131235c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
131335c4bbdfSmrg        for (j = 0; j < numOutputs; j++) {
131435c4bbdfSmrg            int k;
131535c4bbdfSmrg
131635c4bbdfSmrg            if (i == j)
131735c4bbdfSmrg                continue;
131835c4bbdfSmrg            for (k = 0; k < outputs[i]->numClones; k++) {
131935c4bbdfSmrg                if (outputs[i]->clones[k] == outputs[j])
132035c4bbdfSmrg                    break;
132135c4bbdfSmrg            }
132235c4bbdfSmrg            if (k == outputs[i]->numClones) {
132335c4bbdfSmrg                free(outputs);
132435c4bbdfSmrg                return BadMatch;
132535c4bbdfSmrg            }
132635c4bbdfSmrg        }
132705b261ecSmrg    }
132805b261ecSmrg
132905b261ecSmrg    pScreen = crtc->pScreen;
133005b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
133135c4bbdfSmrg
133205b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
133335c4bbdfSmrg
133435c4bbdfSmrg    if (!pScrPriv) {
133535c4bbdfSmrg        time = currentTime;
133635c4bbdfSmrg        status = RRSetConfigFailed;
133735c4bbdfSmrg        goto sendReply;
133805b261ecSmrg    }
133935c4bbdfSmrg
134005b261ecSmrg    /*
134105b261ecSmrg     * Validate requested rotation
134205b261ecSmrg     */
134305b261ecSmrg    rotation = (Rotation) stuff->rotation;
134405b261ecSmrg
134505b261ecSmrg    /* test the rotation bits only! */
134605b261ecSmrg    switch (rotation & 0xf) {
134705b261ecSmrg    case RR_Rotate_0:
134805b261ecSmrg    case RR_Rotate_90:
134905b261ecSmrg    case RR_Rotate_180:
135005b261ecSmrg    case RR_Rotate_270:
135135c4bbdfSmrg        break;
135205b261ecSmrg    default:
135335c4bbdfSmrg        /*
135435c4bbdfSmrg         * Invalid rotation
135535c4bbdfSmrg         */
135635c4bbdfSmrg        client->errorValue = stuff->rotation;
135735c4bbdfSmrg        free(outputs);
135835c4bbdfSmrg        return BadValue;
135905b261ecSmrg    }
136005b261ecSmrg
136135c4bbdfSmrg    if (mode) {
136235c4bbdfSmrg        if ((~crtc->rotations) & rotation) {
136335c4bbdfSmrg            /*
136435c4bbdfSmrg             * requested rotation or reflection not supported by screen
136535c4bbdfSmrg             */
136635c4bbdfSmrg            client->errorValue = stuff->rotation;
136735c4bbdfSmrg            free(outputs);
136835c4bbdfSmrg            return BadMatch;
136935c4bbdfSmrg        }
137035c4bbdfSmrg
137105b261ecSmrg#ifdef RANDR_12_INTERFACE
137235c4bbdfSmrg        /*
137335c4bbdfSmrg         * Check screen size bounds if the DDX provides a 1.2 interface
137435c4bbdfSmrg         * for setting screen size. Else, assume the CrtcSet sets
137535c4bbdfSmrg         * the size along with the mode. If the driver supports transforms,
137635c4bbdfSmrg         * then it must allow crtcs to display a subset of the screen, so
137735c4bbdfSmrg         * only do this check for drivers without transform support.
137835c4bbdfSmrg         */
137935c4bbdfSmrg        if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
138035c4bbdfSmrg            int source_width;
138135c4bbdfSmrg            int source_height;
138235c4bbdfSmrg            PictTransform transform;
138335c4bbdfSmrg            struct pixman_f_transform f_transform, f_inverse;
138435c4bbdfSmrg            int width, height;
138535c4bbdfSmrg
138635c4bbdfSmrg            if (pScreen->isGPU) {
138735c4bbdfSmrg                width = pScreen->current_master->width;
138835c4bbdfSmrg                height = pScreen->current_master->height;
138935c4bbdfSmrg            }
139035c4bbdfSmrg            else {
139135c4bbdfSmrg                width = pScreen->width;
139235c4bbdfSmrg                height = pScreen->height;
139335c4bbdfSmrg            }
139435c4bbdfSmrg
139535c4bbdfSmrg            RRTransformCompute(stuff->x, stuff->y,
139635c4bbdfSmrg                               mode->mode.width, mode->mode.height,
139735c4bbdfSmrg                               rotation,
139835c4bbdfSmrg                               &crtc->client_pending_transform,
139935c4bbdfSmrg                               &transform, &f_transform, &f_inverse);
140035c4bbdfSmrg
140135c4bbdfSmrg            RRModeGetScanoutSize(mode, &transform, &source_width,
140235c4bbdfSmrg                                 &source_height);
140335c4bbdfSmrg            if (stuff->x + source_width > width) {
140435c4bbdfSmrg                client->errorValue = stuff->x;
140535c4bbdfSmrg                free(outputs);
140635c4bbdfSmrg                return BadValue;
140735c4bbdfSmrg            }
140835c4bbdfSmrg
140935c4bbdfSmrg            if (stuff->y + source_height > height) {
141035c4bbdfSmrg                client->errorValue = stuff->y;
141135c4bbdfSmrg                free(outputs);
141235c4bbdfSmrg                return BadValue;
141335c4bbdfSmrg            }
141435c4bbdfSmrg        }
141505b261ecSmrg#endif
141605b261ecSmrg    }
141735c4bbdfSmrg
141835c4bbdfSmrg    if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
141935c4bbdfSmrg                   rotation, numOutputs, outputs)) {
142035c4bbdfSmrg        status = RRSetConfigFailed;
142135c4bbdfSmrg        goto sendReply;
142205b261ecSmrg    }
142335c4bbdfSmrg    status = RRSetConfigSuccess;
142452397711Smrg    pScrPriv->lastSetTime = time;
142535c4bbdfSmrg
142635c4bbdfSmrg sendReply:
14276747b715Smrg    free(outputs);
142835c4bbdfSmrg
142935c4bbdfSmrg    rep = (xRRSetCrtcConfigReply) {
143035c4bbdfSmrg        .type = X_Reply,
143135c4bbdfSmrg        .status = status,
143235c4bbdfSmrg        .sequenceNumber = client->sequence,
143335c4bbdfSmrg        .length = 0,
143435c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
143535c4bbdfSmrg    };
143635c4bbdfSmrg
143735c4bbdfSmrg    if (client->swapped) {
143835c4bbdfSmrg        swaps(&rep.sequenceNumber);
143935c4bbdfSmrg        swapl(&rep.length);
144035c4bbdfSmrg        swapl(&rep.newTimestamp);
144105b261ecSmrg    }
144235c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
144335c4bbdfSmrg
14446747b715Smrg    return Success;
144505b261ecSmrg}
144605b261ecSmrg
14474642e01fSmrgint
144835c4bbdfSmrgProcRRGetPanning(ClientPtr client)
14494642e01fSmrg{
14504642e01fSmrg    REQUEST(xRRGetPanningReq);
145135c4bbdfSmrg    xRRGetPanningReply rep;
145235c4bbdfSmrg    RRCrtcPtr crtc;
145335c4bbdfSmrg    ScreenPtr pScreen;
145435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
145535c4bbdfSmrg    BoxRec total;
145635c4bbdfSmrg    BoxRec tracking;
145735c4bbdfSmrg    INT16 border[4];
145835c4bbdfSmrg
14594642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
14606747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
14614642e01fSmrg
14624642e01fSmrg    /* All crtcs must be associated with screens before client
14634642e01fSmrg     * requests are processed
14644642e01fSmrg     */
14654642e01fSmrg    pScreen = crtc->pScreen;
14664642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
14674642e01fSmrg
14684642e01fSmrg    if (!pScrPriv)
146935c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
14704642e01fSmrg
147135c4bbdfSmrg    rep = (xRRGetPanningReply) {
147235c4bbdfSmrg        .type = X_Reply,
147335c4bbdfSmrg        .status = RRSetConfigSuccess,
147435c4bbdfSmrg        .sequenceNumber = client->sequence,
147535c4bbdfSmrg        .length = 1,
147635c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
147735c4bbdfSmrg    };
14784642e01fSmrg
14794642e01fSmrg    if (pScrPriv->rrGetPanning &&
148035c4bbdfSmrg        pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
148135c4bbdfSmrg        rep.left = total.x1;
148235c4bbdfSmrg        rep.top = total.y1;
148335c4bbdfSmrg        rep.width = total.x2 - total.x1;
148435c4bbdfSmrg        rep.height = total.y2 - total.y1;
148535c4bbdfSmrg        rep.track_left = tracking.x1;
148635c4bbdfSmrg        rep.track_top = tracking.y1;
148735c4bbdfSmrg        rep.track_width = tracking.x2 - tracking.x1;
148835c4bbdfSmrg        rep.track_height = tracking.y2 - tracking.y1;
148935c4bbdfSmrg        rep.border_left = border[0];
149035c4bbdfSmrg        rep.border_top = border[1];
149135c4bbdfSmrg        rep.border_right = border[2];
149235c4bbdfSmrg        rep.border_bottom = border[3];
14934642e01fSmrg    }
14944642e01fSmrg
14954642e01fSmrg    if (client->swapped) {
149635c4bbdfSmrg        swaps(&rep.sequenceNumber);
149735c4bbdfSmrg        swapl(&rep.length);
149835c4bbdfSmrg        swapl(&rep.timestamp);
149935c4bbdfSmrg        swaps(&rep.left);
150035c4bbdfSmrg        swaps(&rep.top);
150135c4bbdfSmrg        swaps(&rep.width);
150235c4bbdfSmrg        swaps(&rep.height);
150335c4bbdfSmrg        swaps(&rep.track_left);
150435c4bbdfSmrg        swaps(&rep.track_top);
150535c4bbdfSmrg        swaps(&rep.track_width);
150635c4bbdfSmrg        swaps(&rep.track_height);
150735c4bbdfSmrg        swaps(&rep.border_left);
150835c4bbdfSmrg        swaps(&rep.border_top);
150935c4bbdfSmrg        swaps(&rep.border_right);
151035c4bbdfSmrg        swaps(&rep.border_bottom);
151135c4bbdfSmrg    }
151235c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
15136747b715Smrg    return Success;
15144642e01fSmrg}
15154642e01fSmrg
15164642e01fSmrgint
151735c4bbdfSmrgProcRRSetPanning(ClientPtr client)
15184642e01fSmrg{
15194642e01fSmrg    REQUEST(xRRSetPanningReq);
152035c4bbdfSmrg    xRRSetPanningReply rep;
152135c4bbdfSmrg    RRCrtcPtr crtc;
152235c4bbdfSmrg    ScreenPtr pScreen;
152335c4bbdfSmrg    rrScrPrivPtr pScrPriv;
152435c4bbdfSmrg    TimeStamp time;
152535c4bbdfSmrg    BoxRec total;
152635c4bbdfSmrg    BoxRec tracking;
152735c4bbdfSmrg    INT16 border[4];
152835c4bbdfSmrg    CARD8 status;
152935c4bbdfSmrg
15304642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
15316747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15324642e01fSmrg
15331b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
15341b5d61b8Smrg        return BadAccess;
15351b5d61b8Smrg
15364642e01fSmrg    /* All crtcs must be associated with screens before client
15374642e01fSmrg     * requests are processed
15384642e01fSmrg     */
15394642e01fSmrg    pScreen = crtc->pScreen;
15404642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
15414642e01fSmrg
15424642e01fSmrg    if (!pScrPriv) {
154335c4bbdfSmrg        time = currentTime;
154435c4bbdfSmrg        status = RRSetConfigFailed;
154535c4bbdfSmrg        goto sendReply;
15464642e01fSmrg    }
154735c4bbdfSmrg
15484642e01fSmrg    time = ClientTimeToServerTime(stuff->timestamp);
154935c4bbdfSmrg
15504642e01fSmrg    if (!pScrPriv->rrGetPanning)
155135c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
15524642e01fSmrg
155335c4bbdfSmrg    total.x1 = stuff->left;
155435c4bbdfSmrg    total.y1 = stuff->top;
155535c4bbdfSmrg    total.x2 = total.x1 + stuff->width;
155635c4bbdfSmrg    total.y2 = total.y1 + stuff->height;
15574642e01fSmrg    tracking.x1 = stuff->track_left;
15584642e01fSmrg    tracking.y1 = stuff->track_top;
15594642e01fSmrg    tracking.x2 = tracking.x1 + stuff->track_width;
15604642e01fSmrg    tracking.y2 = tracking.y1 + stuff->track_height;
156135c4bbdfSmrg    border[0] = stuff->border_left;
156235c4bbdfSmrg    border[1] = stuff->border_top;
156335c4bbdfSmrg    border[2] = stuff->border_right;
156435c4bbdfSmrg    border[3] = stuff->border_bottom;
15654642e01fSmrg
156635c4bbdfSmrg    if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
156735c4bbdfSmrg        return BadMatch;
15684642e01fSmrg
156952397711Smrg    pScrPriv->lastSetTime = time;
157052397711Smrg
157135c4bbdfSmrg    status = RRSetConfigSuccess;
15724642e01fSmrg
157335c4bbdfSmrg sendReply:
157435c4bbdfSmrg    rep = (xRRSetPanningReply) {
157535c4bbdfSmrg        .type = X_Reply,
157635c4bbdfSmrg        .status = status,
157735c4bbdfSmrg        .sequenceNumber = client->sequence,
157835c4bbdfSmrg        .length = 0,
157935c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
158035c4bbdfSmrg    };
15814642e01fSmrg
15824642e01fSmrg    if (client->swapped) {
158335c4bbdfSmrg        swaps(&rep.sequenceNumber);
158435c4bbdfSmrg        swapl(&rep.length);
158535c4bbdfSmrg        swapl(&rep.newTimestamp);
15864642e01fSmrg    }
158735c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
15886747b715Smrg    return Success;
15894642e01fSmrg}
15904642e01fSmrg
159105b261ecSmrgint
159235c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client)
159305b261ecSmrg{
159405b261ecSmrg    REQUEST(xRRGetCrtcGammaSizeReq);
159535c4bbdfSmrg    xRRGetCrtcGammaSizeReply reply;
159635c4bbdfSmrg    RRCrtcPtr crtc;
159705b261ecSmrg
159805b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
15996747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
16006747b715Smrg
16016747b715Smrg    /* Gamma retrieval failed, any better error? */
16026747b715Smrg    if (!RRCrtcGammaGet(crtc))
16036747b715Smrg        return RRErrorBase + BadRRCrtc;
16046747b715Smrg
160535c4bbdfSmrg    reply = (xRRGetCrtcGammaSizeReply) {
160635c4bbdfSmrg        .type = X_Reply,
160735c4bbdfSmrg        .sequenceNumber = client->sequence,
160835c4bbdfSmrg        .length = 0,
160935c4bbdfSmrg        .size = crtc->gammaSize
161035c4bbdfSmrg    };
161105b261ecSmrg    if (client->swapped) {
161235c4bbdfSmrg        swaps(&reply.sequenceNumber);
161335c4bbdfSmrg        swapl(&reply.length);
161435c4bbdfSmrg        swaps(&reply.size);
161505b261ecSmrg    }
161635c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
16176747b715Smrg    return Success;
161805b261ecSmrg}
161905b261ecSmrg
162005b261ecSmrgint
162135c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client)
162205b261ecSmrg{
162305b261ecSmrg    REQUEST(xRRGetCrtcGammaReq);
162435c4bbdfSmrg    xRRGetCrtcGammaReply reply;
162535c4bbdfSmrg    RRCrtcPtr crtc;
162635c4bbdfSmrg    unsigned long len;
162735c4bbdfSmrg    char *extra = NULL;
162835c4bbdfSmrg
162905b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
16306747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
16316747b715Smrg
16326747b715Smrg    /* Gamma retrieval failed, any better error? */
16336747b715Smrg    if (!RRCrtcGammaGet(crtc))
16346747b715Smrg        return RRErrorBase + BadRRCrtc;
16356747b715Smrg
163605b261ecSmrg    len = crtc->gammaSize * 3 * 2;
163735c4bbdfSmrg
16384642e01fSmrg    if (crtc->gammaSize) {
163935c4bbdfSmrg        extra = malloc(len);
164035c4bbdfSmrg        if (!extra)
164135c4bbdfSmrg            return BadAlloc;
16424642e01fSmrg    }
16434642e01fSmrg
164435c4bbdfSmrg    reply = (xRRGetCrtcGammaReply) {
164535c4bbdfSmrg        .type = X_Reply,
164635c4bbdfSmrg        .sequenceNumber = client->sequence,
164735c4bbdfSmrg        .length = bytes_to_int32(len),
164835c4bbdfSmrg        .size = crtc->gammaSize
164935c4bbdfSmrg    };
165005b261ecSmrg    if (client->swapped) {
165135c4bbdfSmrg        swaps(&reply.sequenceNumber);
165235c4bbdfSmrg        swapl(&reply.length);
165335c4bbdfSmrg        swaps(&reply.size);
165405b261ecSmrg    }
165535c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
165635c4bbdfSmrg    if (crtc->gammaSize) {
165735c4bbdfSmrg        memcpy(extra, crtc->gammaRed, len);
165835c4bbdfSmrg        client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
165935c4bbdfSmrg        WriteSwappedDataToClient(client, len, extra);
166035c4bbdfSmrg        free(extra);
166105b261ecSmrg    }
16626747b715Smrg    return Success;
166305b261ecSmrg}
166405b261ecSmrg
166505b261ecSmrgint
166635c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client)
166705b261ecSmrg{
166805b261ecSmrg    REQUEST(xRRSetCrtcGammaReq);
166935c4bbdfSmrg    RRCrtcPtr crtc;
167035c4bbdfSmrg    unsigned long len;
167135c4bbdfSmrg    CARD16 *red, *green, *blue;
167235c4bbdfSmrg
167305b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
16746747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
167535c4bbdfSmrg
16761b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
16771b5d61b8Smrg        return BadAccess;
16781b5d61b8Smrg
167935c4bbdfSmrg    len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
168005b261ecSmrg    if (len < (stuff->size * 3 + 1) >> 1)
168135c4bbdfSmrg        return BadLength;
168205b261ecSmrg
168305b261ecSmrg    if (stuff->size != crtc->gammaSize)
168435c4bbdfSmrg        return BadMatch;
168535c4bbdfSmrg
168605b261ecSmrg    red = (CARD16 *) (stuff + 1);
168705b261ecSmrg    green = red + crtc->gammaSize;
168805b261ecSmrg    blue = green + crtc->gammaSize;
168935c4bbdfSmrg
169035c4bbdfSmrg    RRCrtcGammaSet(crtc, red, green, blue);
169105b261ecSmrg
169205b261ecSmrg    return Success;
169305b261ecSmrg}
169405b261ecSmrg
16954642e01fSmrg/* Version 1.3 additions */
16964642e01fSmrg
16974642e01fSmrgint
169835c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client)
16994642e01fSmrg{
17004642e01fSmrg    REQUEST(xRRSetCrtcTransformReq);
170135c4bbdfSmrg    RRCrtcPtr crtc;
170235c4bbdfSmrg    PictTransform transform;
17034642e01fSmrg    struct pixman_f_transform f_transform, f_inverse;
170435c4bbdfSmrg    char *filter;
170535c4bbdfSmrg    int nbytes;
170635c4bbdfSmrg    xFixed *params;
170735c4bbdfSmrg    int nparams;
17084642e01fSmrg
17094642e01fSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
17106747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
17114642e01fSmrg
17121b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
17131b5d61b8Smrg        return BadAccess;
17141b5d61b8Smrg
171535c4bbdfSmrg    PictTransform_from_xRenderTransform(&transform, &stuff->transform);
171635c4bbdfSmrg    pixman_f_transform_from_pixman_transform(&f_transform, &transform);
171735c4bbdfSmrg    if (!pixman_f_transform_invert(&f_inverse, &f_transform))
171835c4bbdfSmrg        return BadMatch;
17194642e01fSmrg
17204642e01fSmrg    filter = (char *) (stuff + 1);
17214642e01fSmrg    nbytes = stuff->nbytesFilter;
17226747b715Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
17234642e01fSmrg    nparams = ((xFixed *) stuff + client->req_len) - params;
17244642e01fSmrg    if (nparams < 0)
172535c4bbdfSmrg        return BadLength;
17264642e01fSmrg
172735c4bbdfSmrg    return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
172835c4bbdfSmrg                              filter, nbytes, params, nparams);
17294642e01fSmrg}
17304642e01fSmrg
17314642e01fSmrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
173235c4bbdfSmrg
17334642e01fSmrgstatic int
173435c4bbdfSmrgtransform_filter_length(RRTransformPtr transform)
17354642e01fSmrg{
173635c4bbdfSmrg    int nbytes, nparams;
17374642e01fSmrg
17384642e01fSmrg    if (transform->filter == NULL)
173935c4bbdfSmrg        return 0;
174035c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17414642e01fSmrg    nparams = transform->nparams;
174235c4bbdfSmrg    return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
17434642e01fSmrg}
17444642e01fSmrg
17454642e01fSmrgstatic int
174635c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output,
174735c4bbdfSmrg                        CARD16 *nbytesFilter,
174835c4bbdfSmrg                        CARD16 *nparamsFilter, RRTransformPtr transform)
17494642e01fSmrg{
175035c4bbdfSmrg    int nbytes, nparams;
17514642e01fSmrg
17524642e01fSmrg    if (transform->filter == NULL) {
175335c4bbdfSmrg        *nbytesFilter = 0;
175435c4bbdfSmrg        *nparamsFilter = 0;
175535c4bbdfSmrg        return 0;
17564642e01fSmrg    }
175735c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17584642e01fSmrg    nparams = transform->nparams;
17594642e01fSmrg    *nbytesFilter = nbytes;
17604642e01fSmrg    *nparamsFilter = nparams;
176135c4bbdfSmrg    memcpy(output, transform->filter->name, nbytes);
17624642e01fSmrg    while ((nbytes & 3) != 0)
176335c4bbdfSmrg        output[nbytes++] = 0;
176435c4bbdfSmrg    memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
17654642e01fSmrg    if (client->swapped) {
176635c4bbdfSmrg        swaps(nbytesFilter);
176735c4bbdfSmrg        swaps(nparamsFilter);
176835c4bbdfSmrg        SwapLongs((CARD32 *) (output + nbytes), nparams);
17694642e01fSmrg    }
177035c4bbdfSmrg    nbytes += nparams * sizeof(xFixed);
17714642e01fSmrg    return nbytes;
17724642e01fSmrg}
17734642e01fSmrg
17744642e01fSmrgstatic void
177535c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire,
177635c4bbdfSmrg                 PictTransform * pict)
17774642e01fSmrg{
177835c4bbdfSmrg    xRenderTransform_from_PictTransform(wire, pict);
17794642e01fSmrg    if (client->swapped)
178035c4bbdfSmrg        SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
17814642e01fSmrg}
17824642e01fSmrg
17834642e01fSmrgint
178435c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client)
17854642e01fSmrg{
17864642e01fSmrg    REQUEST(xRRGetCrtcTransformReq);
178735c4bbdfSmrg    xRRGetCrtcTransformReply *reply;
178835c4bbdfSmrg    RRCrtcPtr crtc;
178935c4bbdfSmrg    int nextra;
179035c4bbdfSmrg    RRTransformPtr current, pending;
179135c4bbdfSmrg    char *extra;
17924642e01fSmrg
179335c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
17946747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
17954642e01fSmrg
17964642e01fSmrg    pending = &crtc->client_pending_transform;
17974642e01fSmrg    current = &crtc->client_current_transform;
17984642e01fSmrg
179935c4bbdfSmrg    nextra = (transform_filter_length(pending) +
180035c4bbdfSmrg              transform_filter_length(current));
18014642e01fSmrg
180235c4bbdfSmrg    reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
18034642e01fSmrg    if (!reply)
180435c4bbdfSmrg        return BadAlloc;
18054642e01fSmrg
18064642e01fSmrg    extra = (char *) (reply + 1);
18074642e01fSmrg    reply->type = X_Reply;
18084642e01fSmrg    reply->sequenceNumber = client->sequence;
18096747b715Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
18104642e01fSmrg
18114642e01fSmrg    reply->hasTransforms = crtc->transforms;
18124642e01fSmrg
181335c4bbdfSmrg    transform_encode(client, &reply->pendingTransform, &pending->transform);
181435c4bbdfSmrg    extra += transform_filter_encode(client, extra,
181535c4bbdfSmrg                                     &reply->pendingNbytesFilter,
181635c4bbdfSmrg                                     &reply->pendingNparamsFilter, pending);
18174642e01fSmrg
181835c4bbdfSmrg    transform_encode(client, &reply->currentTransform, &current->transform);
181935c4bbdfSmrg    extra += transform_filter_encode(client, extra,
182035c4bbdfSmrg                                     &reply->currentNbytesFilter,
182135c4bbdfSmrg                                     &reply->currentNparamsFilter, current);
18224642e01fSmrg
18234642e01fSmrg    if (client->swapped) {
182435c4bbdfSmrg        swaps(&reply->sequenceNumber);
182535c4bbdfSmrg        swapl(&reply->length);
18264642e01fSmrg    }
182735c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
18286747b715Smrg    free(reply);
18296747b715Smrg    return Success;
18304642e01fSmrg}
183135c4bbdfSmrg
183235c4bbdfSmrgstatic Bool
183335c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
183435c4bbdfSmrg{
183535c4bbdfSmrg    rrScrPriv(pScreen);
183635c4bbdfSmrg    int i;
183735c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
183835c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
183935c4bbdfSmrg
184035c4bbdfSmrg        int left, right, top, bottom;
184135c4bbdfSmrg
18421b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
18431b5d61b8Smrg	    continue;
184435c4bbdfSmrg
184535c4bbdfSmrg        if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
184635c4bbdfSmrg            return TRUE;
184735c4bbdfSmrg    }
184835c4bbdfSmrg    return FALSE;
184935c4bbdfSmrg}
185035c4bbdfSmrg
185135c4bbdfSmrgstatic Bool
185235c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
185335c4bbdfSmrg{
185435c4bbdfSmrg    rrScrPriv(pScreen);
185535c4bbdfSmrg    int i;
185635c4bbdfSmrg
185735c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
185835c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
185935c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
186035c4bbdfSmrg        int nx, ny;
186135c4bbdfSmrg        int left, right, top, bottom;
186235c4bbdfSmrg
18631b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
18641b5d61b8Smrg	    continue;
186535c4bbdfSmrg
186635c4bbdfSmrg        miPointerGetPosition(pDev, &nx, &ny);
186735c4bbdfSmrg
186835c4bbdfSmrg        if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
186935c4bbdfSmrg            if (*x < left)
187035c4bbdfSmrg                *x = left;
187135c4bbdfSmrg            if (*x >= right)
187235c4bbdfSmrg                *x = right - 1;
187335c4bbdfSmrg            if (*y < top)
187435c4bbdfSmrg                *y = top;
187535c4bbdfSmrg            if (*y >= bottom)
187635c4bbdfSmrg                *y = bottom - 1;
187735c4bbdfSmrg
187835c4bbdfSmrg            return TRUE;
187935c4bbdfSmrg        }
188035c4bbdfSmrg    }
188135c4bbdfSmrg    return FALSE;
188235c4bbdfSmrg}
188335c4bbdfSmrg
188435c4bbdfSmrgvoid
188535c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
188635c4bbdfSmrg                        int *y)
188735c4bbdfSmrg{
188835c4bbdfSmrg    rrScrPriv(pScreen);
188935c4bbdfSmrg    Bool ret;
189035c4bbdfSmrg    ScreenPtr slave;
189135c4bbdfSmrg
189235c4bbdfSmrg    /* intentional dead space -> let it float */
189335c4bbdfSmrg    if (pScrPriv->discontiguous)
189435c4bbdfSmrg        return;
189535c4bbdfSmrg
189635c4bbdfSmrg    /* if we're moving inside a crtc, we're fine */
189735c4bbdfSmrg    ret = check_all_screen_crtcs(pScreen, x, y);
189835c4bbdfSmrg    if (ret == TRUE)
189935c4bbdfSmrg        return;
190035c4bbdfSmrg
19011b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
19021b5d61b8Smrg        if (!slave->is_output_slave)
19031b5d61b8Smrg            continue;
19041b5d61b8Smrg
190535c4bbdfSmrg        ret = check_all_screen_crtcs(slave, x, y);
190635c4bbdfSmrg        if (ret == TRUE)
190735c4bbdfSmrg            return;
190835c4bbdfSmrg    }
190935c4bbdfSmrg
191035c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
191135c4bbdfSmrg    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
191235c4bbdfSmrg    if (ret == TRUE)
191335c4bbdfSmrg        return;
191435c4bbdfSmrg
19151b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
19161b5d61b8Smrg        if (!slave->is_output_slave)
19171b5d61b8Smrg            continue;
19181b5d61b8Smrg
191935c4bbdfSmrg        ret = constrain_all_screen_crtcs(pDev, slave, x, y);
192035c4bbdfSmrg        if (ret == TRUE)
192135c4bbdfSmrg            return;
192235c4bbdfSmrg    }
192335c4bbdfSmrg}
192435c4bbdfSmrg
192535c4bbdfSmrgBool
192635c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
192735c4bbdfSmrg{
192835c4bbdfSmrg    rrScrPriv(pDrawable->pScreen);
192935c4bbdfSmrg    Bool ret = TRUE;
193035c4bbdfSmrg    PixmapPtr *saved_scanout_pixmap;
193135c4bbdfSmrg    int i;
193235c4bbdfSmrg
193335c4bbdfSmrg    saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
193435c4bbdfSmrg    if (saved_scanout_pixmap == NULL)
193535c4bbdfSmrg        return FALSE;
193635c4bbdfSmrg
193735c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
193835c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
193935c4bbdfSmrg        Bool size_fits;
194035c4bbdfSmrg
194135c4bbdfSmrg        saved_scanout_pixmap[i] = crtc->scanout_pixmap;
194235c4bbdfSmrg
194335c4bbdfSmrg        if (!crtc->mode && enable)
194435c4bbdfSmrg            continue;
194535c4bbdfSmrg        if (!crtc->scanout_pixmap && !enable)
194635c4bbdfSmrg            continue;
194735c4bbdfSmrg
19481b5d61b8Smrg        /* not supported with double buffering, needs ABI change for 2 ppix */
19491b5d61b8Smrg        if (crtc->scanout_pixmap_back) {
19501b5d61b8Smrg            ret = FALSE;
19511b5d61b8Smrg            continue;
19521b5d61b8Smrg        }
19531b5d61b8Smrg
195435c4bbdfSmrg        size_fits = (crtc->mode &&
195535c4bbdfSmrg                     crtc->x == pDrawable->x &&
195635c4bbdfSmrg                     crtc->y == pDrawable->y &&
195735c4bbdfSmrg                     crtc->mode->mode.width == pDrawable->width &&
195835c4bbdfSmrg                     crtc->mode->mode.height == pDrawable->height);
195935c4bbdfSmrg
196035c4bbdfSmrg        /* is the pixmap already set? */
196135c4bbdfSmrg        if (crtc->scanout_pixmap == pPixmap) {
196235c4bbdfSmrg            /* if its a disable then don't care about size */
196335c4bbdfSmrg            if (enable == FALSE) {
196435c4bbdfSmrg                /* set scanout to NULL */
196535c4bbdfSmrg                crtc->scanout_pixmap = NULL;
196635c4bbdfSmrg            }
196735c4bbdfSmrg            else if (!size_fits) {
196835c4bbdfSmrg                /* if the size no longer fits then drop off */
196935c4bbdfSmrg                crtc->scanout_pixmap = NULL;
197035c4bbdfSmrg                pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
197135c4bbdfSmrg
197235c4bbdfSmrg                (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
197335c4bbdfSmrg                                        crtc->rotation, crtc->numOutputs, crtc->outputs);
197435c4bbdfSmrg                saved_scanout_pixmap[i] = crtc->scanout_pixmap;
197535c4bbdfSmrg                ret = FALSE;
197635c4bbdfSmrg            }
197735c4bbdfSmrg            else {
197835c4bbdfSmrg                /* if the size fits then we are already setup */
197935c4bbdfSmrg            }
198035c4bbdfSmrg        }
198135c4bbdfSmrg        else {
198235c4bbdfSmrg            if (!size_fits)
198335c4bbdfSmrg                ret = FALSE;
198435c4bbdfSmrg            else if (enable)
198535c4bbdfSmrg                crtc->scanout_pixmap = pPixmap;
198635c4bbdfSmrg            else
198735c4bbdfSmrg                /* reject an attempt to disable someone else's scanout_pixmap */
198835c4bbdfSmrg                ret = FALSE;
198935c4bbdfSmrg        }
199035c4bbdfSmrg    }
199135c4bbdfSmrg
199235c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
199335c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
199435c4bbdfSmrg
199535c4bbdfSmrg        if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
199635c4bbdfSmrg            continue;
199735c4bbdfSmrg
199835c4bbdfSmrg        if (ret) {
199935c4bbdfSmrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
200035c4bbdfSmrg
200135c4bbdfSmrg            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
200235c4bbdfSmrg                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
200335c4bbdfSmrg        }
200435c4bbdfSmrg        else
200535c4bbdfSmrg            crtc->scanout_pixmap = saved_scanout_pixmap[i];
200635c4bbdfSmrg    }
200735c4bbdfSmrg    free(saved_scanout_pixmap);
200835c4bbdfSmrg
200935c4bbdfSmrg    return ret;
201035c4bbdfSmrg}
20111b5d61b8Smrg
20121b5d61b8SmrgBool
20131b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen)
20141b5d61b8Smrg{
20151b5d61b8Smrg    rrScrPriv(pScreen);
20161b5d61b8Smrg    int i;
20171b5d61b8Smrg
20181b5d61b8Smrg    if (!pScreen->is_output_slave)
20191b5d61b8Smrg        return FALSE;
20201b5d61b8Smrg
20211b5d61b8Smrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
20221b5d61b8Smrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
20231b5d61b8Smrg
20241b5d61b8Smrg        if (crtc->scanout_pixmap)
20251b5d61b8Smrg            return TRUE;
20261b5d61b8Smrg    }
20271b5d61b8Smrg
20281b5d61b8Smrg    return FALSE;
20291b5d61b8Smrg}
2030