rrcrtc.c revision 1b5d61b8
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
4041b5d61b8Smrg            master->StopFlippingPixmapTracking(mrootdraw,
4051b5d61b8Smrg                                               crtc->scanout_pixmap,
4061b5d61b8Smrg                                               crtc->scanout_pixmap_back);
40735c4bbdfSmrg
4081b5d61b8Smrg            rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back);
4091b5d61b8Smrg            crtc->scanout_pixmap_back = NULL;
4101b5d61b8Smrg        }
4111b5d61b8Smrg        else {
4121b5d61b8Smrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
4131b5d61b8Smrg            master->StopPixmapTracking(mrootdraw,
4141b5d61b8Smrg                                       crtc->scanout_pixmap);
4151b5d61b8Smrg        }
4161b5d61b8Smrg
4171b5d61b8Smrg        rrDestroySharedPixmap(crtc, crtc->scanout_pixmap);
4181b5d61b8Smrg        crtc->scanout_pixmap = NULL;
41935c4bbdfSmrg    }
42035c4bbdfSmrg
4211b5d61b8Smrg    RRCrtcChanged(crtc, TRUE);
4221b5d61b8Smrg}
4231b5d61b8Smrg
4241b5d61b8Smrgstatic PixmapPtr
4251b5d61b8SmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
4261b5d61b8Smrg                     int width, int height, int depth,
4271b5d61b8Smrg                     int x, int y, Rotation rotation)
4281b5d61b8Smrg{
4291b5d61b8Smrg    PixmapPtr mpix, spix;
4301b5d61b8Smrg
43135c4bbdfSmrg    mpix = master->CreatePixmap(master, width, height, depth,
43235c4bbdfSmrg                                CREATE_PIXMAP_USAGE_SHARED);
43335c4bbdfSmrg    if (!mpix)
4341b5d61b8Smrg        return NULL;
43535c4bbdfSmrg
43635c4bbdfSmrg    spix = PixmapShareToSlave(mpix, crtc->pScreen);
43735c4bbdfSmrg    if (spix == NULL) {
43835c4bbdfSmrg        master->DestroyPixmap(mpix);
4391b5d61b8Smrg        return NULL;
4401b5d61b8Smrg    }
4411b5d61b8Smrg
4421b5d61b8Smrg    return spix;
4431b5d61b8Smrg}
4441b5d61b8Smrg
4451b5d61b8Smrgstatic Bool
4461b5d61b8SmrgrrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs)
4471b5d61b8Smrg{
4481b5d61b8Smrg    /* Determine if the user wants prime syncing */
4491b5d61b8Smrg    int o;
4501b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
4511b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
4521b5d61b8Smrg    if (syncProp == None)
4531b5d61b8Smrg        return TRUE;
4541b5d61b8Smrg
4551b5d61b8Smrg    /* If one output doesn't want sync, no sync */
4561b5d61b8Smrg    for (o = 0; o < numOutputs; o++) {
4571b5d61b8Smrg        RRPropertyValuePtr val;
4581b5d61b8Smrg
4591b5d61b8Smrg        /* Try pending value first, then current value */
4601b5d61b8Smrg        if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) &&
4611b5d61b8Smrg            val->data) {
4621b5d61b8Smrg            if (!(*(char *) val->data))
4631b5d61b8Smrg                return FALSE;
4641b5d61b8Smrg            continue;
4651b5d61b8Smrg        }
4661b5d61b8Smrg
4671b5d61b8Smrg        if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) &&
4681b5d61b8Smrg            val->data) {
4691b5d61b8Smrg            if (!(*(char *) val->data))
4701b5d61b8Smrg                return FALSE;
4711b5d61b8Smrg            continue;
4721b5d61b8Smrg        }
4731b5d61b8Smrg    }
4741b5d61b8Smrg
4751b5d61b8Smrg    return TRUE;
4761b5d61b8Smrg}
4771b5d61b8Smrg
4781b5d61b8Smrgstatic void
4791b5d61b8SmrgrrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs)
4801b5d61b8Smrg{
4811b5d61b8Smrg    int o;
4821b5d61b8Smrg    const char *syncStr = PRIME_SYNC_PROP;
4831b5d61b8Smrg    Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
4841b5d61b8Smrg    if (syncProp == None)
4851b5d61b8Smrg        return;
4861b5d61b8Smrg
4871b5d61b8Smrg    for (o = 0; o < numOutputs; o++) {
4881b5d61b8Smrg        RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp);
4891b5d61b8Smrg        if (prop)
4901b5d61b8Smrg            RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER,
4911b5d61b8Smrg                                   8, PropModeReplace, 1, &val, FALSE, TRUE);
4921b5d61b8Smrg    }
4931b5d61b8Smrg}
4941b5d61b8Smrg
4951b5d61b8Smrgstatic Bool
4961b5d61b8SmrgrrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
4971b5d61b8Smrg                     int x, int y, Rotation rotation, Bool sync,
4981b5d61b8Smrg                     int numOutputs, RROutputPtr * outputs)
4991b5d61b8Smrg{
5001b5d61b8Smrg    ScreenPtr master = crtc->pScreen->current_master;
5011b5d61b8Smrg    rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master);
5021b5d61b8Smrg    rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen);
5031b5d61b8Smrg    DrawablePtr mrootdraw = &master->root->drawable;
5041b5d61b8Smrg    int depth = mrootdraw->depth;
5051b5d61b8Smrg    PixmapPtr spix_front;
5061b5d61b8Smrg
5071b5d61b8Smrg    /* Create a pixmap on the master screen, then get a shared handle for it.
5081b5d61b8Smrg       Create a shared pixmap on the slave screen using the handle.
5091b5d61b8Smrg
5101b5d61b8Smrg       If sync == FALSE --
5111b5d61b8Smrg       Set slave screen to scanout shared linear pixmap.
5121b5d61b8Smrg       Set the master screen to do dirty updates to the shared pixmap
5131b5d61b8Smrg       from the screen pixmap on its own accord.
5141b5d61b8Smrg
5151b5d61b8Smrg       If sync == TRUE --
5161b5d61b8Smrg       If any of the below steps fail, clean up and fall back to sync == FALSE.
5171b5d61b8Smrg       Create another shared pixmap on the slave screen using the handle.
5181b5d61b8Smrg       Set slave screen to prepare for scanout and flipping between shared
5191b5d61b8Smrg       linear pixmaps.
5201b5d61b8Smrg       Set the master screen to do dirty updates to the shared pixmaps from the
5211b5d61b8Smrg       screen pixmap when prompted to by us or the slave.
5221b5d61b8Smrg       Prompt the master to do a dirty update on the first shared pixmap, then
5231b5d61b8Smrg       defer to the slave.
5241b5d61b8Smrg    */
5251b5d61b8Smrg
5261b5d61b8Smrg    if (crtc->scanout_pixmap)
5271b5d61b8Smrg        RRCrtcDetachScanoutPixmap(crtc);
5281b5d61b8Smrg
5291b5d61b8Smrg    if (width == 0 && height == 0) {
5301b5d61b8Smrg        return TRUE;
5311b5d61b8Smrg    }
5321b5d61b8Smrg
5331b5d61b8Smrg    spix_front = rrCreateSharedPixmap(crtc, master,
5341b5d61b8Smrg                                      width, height, depth,
5351b5d61b8Smrg                                      x, y, rotation);
5361b5d61b8Smrg    if (spix_front == NULL) {
5371b5d61b8Smrg        ErrorF("randr: failed to create shared pixmap\n");
53835c4bbdfSmrg        return FALSE;
53935c4bbdfSmrg    }
54035c4bbdfSmrg
5411b5d61b8Smrg    /* Both source and sink must support required ABI funcs for flipping */
5421b5d61b8Smrg    if (sync &&
5431b5d61b8Smrg        pSlaveScrPriv->rrEnableSharedPixmapFlipping &&
5441b5d61b8Smrg        pSlaveScrPriv->rrDisableSharedPixmapFlipping &&
5451b5d61b8Smrg        pMasterScrPriv->rrStartFlippingPixmapTracking &&
5461b5d61b8Smrg        master->PresentSharedPixmap &&
5471b5d61b8Smrg        master->StopFlippingPixmapTracking) {
5481b5d61b8Smrg
5491b5d61b8Smrg        PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master,
5501b5d61b8Smrg                                                   width, height, depth,
5511b5d61b8Smrg                                                   x, y, rotation);
5521b5d61b8Smrg        if (spix_back == NULL)
5531b5d61b8Smrg            goto fail;
5541b5d61b8Smrg
5551b5d61b8Smrg        if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc,
5561b5d61b8Smrg                                                         spix_front, spix_back))
5571b5d61b8Smrg            goto fail;
5581b5d61b8Smrg
5591b5d61b8Smrg        crtc->scanout_pixmap = spix_front;
5601b5d61b8Smrg        crtc->scanout_pixmap_back = spix_back;
5611b5d61b8Smrg
5621b5d61b8Smrg        if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc,
5631b5d61b8Smrg                                                           mrootdraw,
5641b5d61b8Smrg                                                           spix_front,
5651b5d61b8Smrg                                                           spix_back,
5661b5d61b8Smrg                                                           x, y, 0, 0,
5671b5d61b8Smrg                                                           rotation)) {
5681b5d61b8Smrg            pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc);
5691b5d61b8Smrg            goto fail;
5701b5d61b8Smrg        }
5711b5d61b8Smrg
5721b5d61b8Smrg        master->PresentSharedPixmap(spix_front);
5731b5d61b8Smrg
5741b5d61b8Smrg        return TRUE;
5751b5d61b8Smrg
5761b5d61b8Smrgfail: /* If flipping funcs fail, just fall back to unsynchronized */
5771b5d61b8Smrg        if (spix_back)
5781b5d61b8Smrg            rrDestroySharedPixmap(crtc, spix_back);
5791b5d61b8Smrg
5801b5d61b8Smrg        crtc->scanout_pixmap = NULL;
5811b5d61b8Smrg        crtc->scanout_pixmap_back = NULL;
5821b5d61b8Smrg    }
5831b5d61b8Smrg
5841b5d61b8Smrg    if (sync) { /* Wanted sync, didn't get it */
5851b5d61b8Smrg        ErrorF("randr: falling back to unsynchronized pixmap sharing\n");
5861b5d61b8Smrg
5871b5d61b8Smrg        /* Set output property to 0 to indicate to user */
5881b5d61b8Smrg        rrSetPixmapSharingSyncProp(0, numOutputs, outputs);
5891b5d61b8Smrg    }
5901b5d61b8Smrg
5911b5d61b8Smrg    if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
5921b5d61b8Smrg        rrDestroySharedPixmap(crtc, spix_front);
59335c4bbdfSmrg        ErrorF("randr: failed to set shadow slave pixmap\n");
59435c4bbdfSmrg        return FALSE;
59535c4bbdfSmrg    }
5961b5d61b8Smrg    crtc->scanout_pixmap = spix_front;
59735c4bbdfSmrg
5981b5d61b8Smrg    master->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation);
59935c4bbdfSmrg
60035c4bbdfSmrg    return TRUE;
60135c4bbdfSmrg}
60235c4bbdfSmrg
60335c4bbdfSmrgstatic void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
60435c4bbdfSmrg{
60535c4bbdfSmrg    box->x1 = crtc->x;
60635c4bbdfSmrg    box->y1 = crtc->y;
60735c4bbdfSmrg    switch (crtc->rotation) {
60835c4bbdfSmrg    case RR_Rotate_0:
60935c4bbdfSmrg    case RR_Rotate_180:
61035c4bbdfSmrg    default:
61135c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.width;
61235c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.height;
61335c4bbdfSmrg        break;
61435c4bbdfSmrg    case RR_Rotate_90:
61535c4bbdfSmrg    case RR_Rotate_270:
61635c4bbdfSmrg        box->x2 = crtc->x + crtc->mode->mode.height;
61735c4bbdfSmrg        box->y2 = crtc->y + crtc->mode->mode.width;
61835c4bbdfSmrg        break;
61935c4bbdfSmrg    }
62035c4bbdfSmrg}
62135c4bbdfSmrg
62235c4bbdfSmrgstatic Bool
62335c4bbdfSmrgrrCheckPixmapBounding(ScreenPtr pScreen,
62435c4bbdfSmrg                      RRCrtcPtr rr_crtc, Rotation rotation,
62535c4bbdfSmrg                      int x, int y, int w, int h)
62635c4bbdfSmrg{
62735c4bbdfSmrg    RegionRec root_pixmap_region, total_region, new_crtc_region;
62835c4bbdfSmrg    int c;
62935c4bbdfSmrg    BoxRec newbox;
63035c4bbdfSmrg    BoxPtr newsize;
63135c4bbdfSmrg    ScreenPtr slave;
63235c4bbdfSmrg    int new_width, new_height;
63335c4bbdfSmrg    PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
63435c4bbdfSmrg    rrScrPriv(pScreen);
63535c4bbdfSmrg
63635c4bbdfSmrg    PixmapRegionInit(&root_pixmap_region, screen_pixmap);
63735c4bbdfSmrg    RegionInit(&total_region, NULL, 0);
63835c4bbdfSmrg
63935c4bbdfSmrg    /* have to iterate all the crtcs of the attached gpu masters
64035c4bbdfSmrg       and all their output slaves */
64135c4bbdfSmrg    for (c = 0; c < pScrPriv->numCrtcs; c++) {
64235c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[c];
64335c4bbdfSmrg
64435c4bbdfSmrg        if (crtc == rr_crtc) {
64535c4bbdfSmrg            newbox.x1 = x;
64635c4bbdfSmrg            newbox.y1 = y;
64735c4bbdfSmrg            if (rotation == RR_Rotate_90 ||
64835c4bbdfSmrg                rotation == RR_Rotate_270) {
64935c4bbdfSmrg                newbox.x2 = x + h;
65035c4bbdfSmrg                newbox.y2 = y + w;
65135c4bbdfSmrg            } else {
65235c4bbdfSmrg                newbox.x2 = x + w;
65335c4bbdfSmrg                newbox.y2 = y + h;
65435c4bbdfSmrg            }
65535c4bbdfSmrg        } else {
65635c4bbdfSmrg            if (!crtc->mode)
65735c4bbdfSmrg                continue;
65835c4bbdfSmrg            crtc_to_box(&newbox, crtc);
65935c4bbdfSmrg        }
66035c4bbdfSmrg        RegionInit(&new_crtc_region, &newbox, 1);
66135c4bbdfSmrg        RegionUnion(&total_region, &total_region, &new_crtc_region);
66235c4bbdfSmrg    }
66335c4bbdfSmrg
6641b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
66535c4bbdfSmrg        rrScrPrivPtr    slave_priv = rrGetScrPriv(slave);
6661b5d61b8Smrg
6671b5d61b8Smrg        if (!slave->is_output_slave)
6681b5d61b8Smrg            continue;
6691b5d61b8Smrg
67035c4bbdfSmrg        for (c = 0; c < slave_priv->numCrtcs; c++) {
67135c4bbdfSmrg            RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
67235c4bbdfSmrg
67335c4bbdfSmrg            if (slave_crtc == rr_crtc) {
67435c4bbdfSmrg                newbox.x1 = x;
67535c4bbdfSmrg                newbox.y1 = y;
67635c4bbdfSmrg                if (rotation == RR_Rotate_90 ||
67735c4bbdfSmrg                    rotation == RR_Rotate_270) {
67835c4bbdfSmrg                    newbox.x2 = x + h;
67935c4bbdfSmrg                    newbox.y2 = y + w;
68035c4bbdfSmrg                } else {
68135c4bbdfSmrg                    newbox.x2 = x + w;
68235c4bbdfSmrg                    newbox.y2 = y + h;
68335c4bbdfSmrg                }
68435c4bbdfSmrg            }
68535c4bbdfSmrg            else {
68635c4bbdfSmrg                if (!slave_crtc->mode)
68735c4bbdfSmrg                    continue;
68835c4bbdfSmrg                crtc_to_box(&newbox, slave_crtc);
68935c4bbdfSmrg            }
69035c4bbdfSmrg            RegionInit(&new_crtc_region, &newbox, 1);
69135c4bbdfSmrg            RegionUnion(&total_region, &total_region, &new_crtc_region);
69235c4bbdfSmrg        }
69335c4bbdfSmrg    }
69435c4bbdfSmrg
69535c4bbdfSmrg    newsize = RegionExtents(&total_region);
6961b5d61b8Smrg    new_width = newsize->x2;
6971b5d61b8Smrg    new_height = newsize->y2;
6981b5d61b8Smrg
6991b5d61b8Smrg    if (new_width < screen_pixmap->drawable.width)
7001b5d61b8Smrg        new_width = screen_pixmap->drawable.width;
70135c4bbdfSmrg
7021b5d61b8Smrg    if (new_height < screen_pixmap->drawable.height)
7031b5d61b8Smrg        new_height = screen_pixmap->drawable.height;
7041b5d61b8Smrg
7051b5d61b8Smrg    if (new_width <= screen_pixmap->drawable.width &&
7061b5d61b8Smrg        new_height <= screen_pixmap->drawable.height) {
70735c4bbdfSmrg    } else {
70835c4bbdfSmrg        pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
70935c4bbdfSmrg    }
71035c4bbdfSmrg
71135c4bbdfSmrg    /* set shatters TODO */
71235c4bbdfSmrg    return TRUE;
71305b261ecSmrg}
71405b261ecSmrg
71505b261ecSmrg/*
71605b261ecSmrg * Request that the Crtc be reconfigured
71705b261ecSmrg */
71805b261ecSmrgBool
71935c4bbdfSmrgRRCrtcSet(RRCrtcPtr crtc,
72035c4bbdfSmrg          RRModePtr mode,
72135c4bbdfSmrg          int x,
72235c4bbdfSmrg          int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
72305b261ecSmrg{
72435c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
72535c4bbdfSmrg    Bool ret = FALSE;
72635c4bbdfSmrg    Bool recompute = TRUE;
72735c4bbdfSmrg    Bool crtcChanged;
72835c4bbdfSmrg    int  o;
72935c4bbdfSmrg
73005b261ecSmrg    rrScrPriv(pScreen);
73105b261ecSmrg
73235c4bbdfSmrg    crtcChanged = FALSE;
73335c4bbdfSmrg    for (o = 0; o < numOutputs; o++) {
73435c4bbdfSmrg        if (outputs[o] && outputs[o]->crtc != crtc) {
73535c4bbdfSmrg            crtcChanged = TRUE;
73635c4bbdfSmrg            break;
73735c4bbdfSmrg        }
73835c4bbdfSmrg    }
73935c4bbdfSmrg
74005b261ecSmrg    /* See if nothing changed */
74105b261ecSmrg    if (crtc->mode == mode &&
74235c4bbdfSmrg        crtc->x == x &&
74335c4bbdfSmrg        crtc->y == y &&
74435c4bbdfSmrg        crtc->rotation == rotation &&
74535c4bbdfSmrg        crtc->numOutputs == numOutputs &&
74635c4bbdfSmrg        !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
74735c4bbdfSmrg        !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
74835c4bbdfSmrg        !crtcChanged) {
74935c4bbdfSmrg        recompute = FALSE;
75035c4bbdfSmrg        ret = TRUE;
75105b261ecSmrg    }
75235c4bbdfSmrg    else {
75335c4bbdfSmrg        if (pScreen->isGPU) {
75435c4bbdfSmrg            ScreenPtr master = pScreen->current_master;
75535c4bbdfSmrg            int width = 0, height = 0;
75635c4bbdfSmrg
75735c4bbdfSmrg            if (mode) {
75835c4bbdfSmrg                width = mode->mode.width;
75935c4bbdfSmrg                height = mode->mode.height;
76035c4bbdfSmrg            }
76135c4bbdfSmrg            ret = rrCheckPixmapBounding(master, crtc,
76235c4bbdfSmrg                                        rotation, x, y, width, height);
76335c4bbdfSmrg            if (!ret)
76435c4bbdfSmrg                return FALSE;
76535c4bbdfSmrg
76635c4bbdfSmrg            if (pScreen->current_master) {
7671b5d61b8Smrg                Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs);
7681b5d61b8Smrg                ret = rrSetupPixmapSharing(crtc, width, height,
7691b5d61b8Smrg                                           x, y, rotation, sync,
7701b5d61b8Smrg                                           numOutputs, outputs);
77135c4bbdfSmrg            }
77235c4bbdfSmrg        }
77305b261ecSmrg#if RANDR_12_INTERFACE
77435c4bbdfSmrg        if (pScrPriv->rrCrtcSet) {
77535c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
77635c4bbdfSmrg                                          rotation, numOutputs, outputs);
77735c4bbdfSmrg        }
77835c4bbdfSmrg        else
77905b261ecSmrg#endif
78035c4bbdfSmrg        {
78105b261ecSmrg#if RANDR_10_INTERFACE
78235c4bbdfSmrg            if (pScrPriv->rrSetConfig) {
78335c4bbdfSmrg                RRScreenSize size;
78435c4bbdfSmrg                RRScreenRate rate;
78535c4bbdfSmrg
78635c4bbdfSmrg                if (!mode) {
78735c4bbdfSmrg                    RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
78835c4bbdfSmrg                    ret = TRUE;
78935c4bbdfSmrg                }
79035c4bbdfSmrg                else {
79135c4bbdfSmrg                    size.width = mode->mode.width;
79235c4bbdfSmrg                    size.height = mode->mode.height;
79335c4bbdfSmrg                    if (outputs[0]->mmWidth && outputs[0]->mmHeight) {
79435c4bbdfSmrg                        size.mmWidth = outputs[0]->mmWidth;
79535c4bbdfSmrg                        size.mmHeight = outputs[0]->mmHeight;
79635c4bbdfSmrg                    }
79735c4bbdfSmrg                    else {
79835c4bbdfSmrg                        size.mmWidth = pScreen->mmWidth;
79935c4bbdfSmrg                        size.mmHeight = pScreen->mmHeight;
80035c4bbdfSmrg                    }
80135c4bbdfSmrg                    size.nRates = 1;
80235c4bbdfSmrg                    rate.rate = RRVerticalRefresh(&mode->mode);
80335c4bbdfSmrg                    size.pRates = &rate;
80435c4bbdfSmrg                    ret =
80535c4bbdfSmrg                        (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate,
80635c4bbdfSmrg                                                  &size);
80735c4bbdfSmrg                    /*
80835c4bbdfSmrg                     * Old 1.0 interface tied screen size to mode size
80935c4bbdfSmrg                     */
81035c4bbdfSmrg                    if (ret) {
81135c4bbdfSmrg                        RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
81235c4bbdfSmrg                                     outputs);
81335c4bbdfSmrg                        RRScreenSizeNotify(pScreen);
81435c4bbdfSmrg                    }
81535c4bbdfSmrg                }
81635c4bbdfSmrg            }
81705b261ecSmrg#endif
81835c4bbdfSmrg        }
81935c4bbdfSmrg        if (ret) {
82005b261ecSmrg
82135c4bbdfSmrg            RRTellChanged(pScreen);
82235c4bbdfSmrg
82335c4bbdfSmrg            for (o = 0; o < numOutputs; o++)
82435c4bbdfSmrg                RRPostPendingProperties(outputs[o]);
82535c4bbdfSmrg        }
82605b261ecSmrg    }
82735c4bbdfSmrg
82835c4bbdfSmrg    if (recompute)
82935c4bbdfSmrg        RRComputeContiguity(pScreen);
83035c4bbdfSmrg
83105b261ecSmrg    return ret;
83205b261ecSmrg}
83305b261ecSmrg
8344642e01fSmrg/*
8354642e01fSmrg * Return crtc transform
8364642e01fSmrg */
8374642e01fSmrgRRTransformPtr
83835c4bbdfSmrgRRCrtcGetTransform(RRCrtcPtr crtc)
8394642e01fSmrg{
84035c4bbdfSmrg    RRTransformPtr transform = &crtc->client_pending_transform;
8414642e01fSmrg
84235c4bbdfSmrg    if (pixman_transform_is_identity(&transform->transform))
84335c4bbdfSmrg        return NULL;
8444642e01fSmrg    return transform;
8454642e01fSmrg}
8464642e01fSmrg
8474642e01fSmrg/*
8484642e01fSmrg * Check whether the pending and current transforms are the same
8494642e01fSmrg */
8504642e01fSmrgBool
85135c4bbdfSmrgRRCrtcPendingTransform(RRCrtcPtr crtc)
8524642e01fSmrg{
8531b5d61b8Smrg    return !RRTransformEqual(&crtc->client_current_transform,
8541b5d61b8Smrg                             &crtc->client_pending_transform);
8554642e01fSmrg}
8564642e01fSmrg
85705b261ecSmrg/*
85805b261ecSmrg * Destroy a Crtc at shutdown
85905b261ecSmrg */
86005b261ecSmrgvoid
86135c4bbdfSmrgRRCrtcDestroy(RRCrtcPtr crtc)
86205b261ecSmrg{
86335c4bbdfSmrg    FreeResource(crtc->id, 0);
86405b261ecSmrg}
86505b261ecSmrg
86605b261ecSmrgstatic int
86735c4bbdfSmrgRRCrtcDestroyResource(void *value, XID pid)
86805b261ecSmrg{
86935c4bbdfSmrg    RRCrtcPtr crtc = (RRCrtcPtr) value;
87035c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
87105b261ecSmrg
87235c4bbdfSmrg    if (pScreen) {
87335c4bbdfSmrg        rrScrPriv(pScreen);
87435c4bbdfSmrg        int i;
8751b5d61b8Smrg        RRLeasePtr lease, next;
8761b5d61b8Smrg
8771b5d61b8Smrg        xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) {
8781b5d61b8Smrg            int c;
8791b5d61b8Smrg            for (c = 0; c < lease->numCrtcs; c++) {
8801b5d61b8Smrg                if (lease->crtcs[c] == crtc) {
8811b5d61b8Smrg                    RRTerminateLease(lease);
8821b5d61b8Smrg                    break;
8831b5d61b8Smrg                }
8841b5d61b8Smrg            }
8851b5d61b8Smrg        }
88635c4bbdfSmrg
88735c4bbdfSmrg        for (i = 0; i < pScrPriv->numCrtcs; i++) {
88835c4bbdfSmrg            if (pScrPriv->crtcs[i] == crtc) {
88935c4bbdfSmrg                memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
89035c4bbdfSmrg                        (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr));
89135c4bbdfSmrg                --pScrPriv->numCrtcs;
89235c4bbdfSmrg                break;
89335c4bbdfSmrg            }
89435c4bbdfSmrg        }
89535c4bbdfSmrg
89635c4bbdfSmrg        RRResourcesChanged(pScreen);
89705b261ecSmrg    }
89835c4bbdfSmrg
89935c4bbdfSmrg    if (crtc->scanout_pixmap)
90035c4bbdfSmrg        RRCrtcDetachScanoutPixmap(crtc);
9016747b715Smrg    free(crtc->gammaRed);
90205b261ecSmrg    if (crtc->mode)
90335c4bbdfSmrg        RRModeDestroy(crtc->mode);
9041b5d61b8Smrg    free(crtc->outputs);
9056747b715Smrg    free(crtc);
90605b261ecSmrg    return 1;
90705b261ecSmrg}
90805b261ecSmrg
90905b261ecSmrg/*
91005b261ecSmrg * Request that the Crtc gamma be changed
91105b261ecSmrg */
91205b261ecSmrg
91305b261ecSmrgBool
91435c4bbdfSmrgRRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
91505b261ecSmrg{
91635c4bbdfSmrg    Bool ret = TRUE;
91735c4bbdfSmrg
91805b261ecSmrg#if RANDR_12_INTERFACE
91935c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
92005b261ecSmrg#endif
92135c4bbdfSmrg
92235c4bbdfSmrg    memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16));
92335c4bbdfSmrg    memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16));
92435c4bbdfSmrg    memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16));
92505b261ecSmrg#if RANDR_12_INTERFACE
92635c4bbdfSmrg    if (pScreen) {
92735c4bbdfSmrg        rrScrPriv(pScreen);
92835c4bbdfSmrg        if (pScrPriv->rrCrtcSetGamma)
92935c4bbdfSmrg            ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
93005b261ecSmrg    }
93105b261ecSmrg#endif
93205b261ecSmrg    return ret;
93305b261ecSmrg}
93405b261ecSmrg
9356747b715Smrg/*
9366747b715Smrg * Request current gamma back from the DDX (if possible).
9376747b715Smrg * This includes gamma size.
9386747b715Smrg */
9396747b715SmrgBool
9406747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc)
9416747b715Smrg{
9426747b715Smrg    Bool ret = TRUE;
94335c4bbdfSmrg
9446747b715Smrg#if RANDR_12_INTERFACE
94535c4bbdfSmrg    ScreenPtr pScreen = crtc->pScreen;
9466747b715Smrg#endif
9476747b715Smrg
9486747b715Smrg#if RANDR_12_INTERFACE
94935c4bbdfSmrg    if (pScreen) {
9506747b715Smrg        rrScrPriv(pScreen);
9516747b715Smrg        if (pScrPriv->rrCrtcGetGamma)
9526747b715Smrg            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
9536747b715Smrg    }
9546747b715Smrg#endif
9556747b715Smrg    return ret;
9566747b715Smrg}
9576747b715Smrg
95805b261ecSmrg/*
95905b261ecSmrg * Notify the extension that the Crtc gamma has been changed
96005b261ecSmrg * The driver calls this whenever it has changed the gamma values
96105b261ecSmrg * in the RRCrtcRec
96205b261ecSmrg */
96305b261ecSmrg
96405b261ecSmrgBool
96535c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc)
96605b261ecSmrg{
96735c4bbdfSmrg    return TRUE;                /* not much going on here */
96805b261ecSmrg}
96905b261ecSmrg
9704642e01fSmrgstatic void
97135c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
97235c4bbdfSmrg                     int *width, int *height)
97305b261ecSmrg{
97435c4bbdfSmrg    BoxRec box;
9754642e01fSmrg
9764642e01fSmrg    if (mode == NULL) {
97735c4bbdfSmrg        *width = 0;
97835c4bbdfSmrg        *height = 0;
97935c4bbdfSmrg        return;
98005b261ecSmrg    }
98105b261ecSmrg
9824642e01fSmrg    box.x1 = 0;
9834642e01fSmrg    box.y1 = 0;
9844642e01fSmrg    box.x2 = mode->mode.width;
9854642e01fSmrg    box.y2 = mode->mode.height;
9864642e01fSmrg
98735c4bbdfSmrg    pixman_transform_bounds(transform, &box);
9884642e01fSmrg    *width = box.x2 - box.x1;
9894642e01fSmrg    *height = box.y2 - box.y1;
9904642e01fSmrg}
9914642e01fSmrg
9924642e01fSmrg/**
9934642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer
9944642e01fSmrg */
9954642e01fSmrgvoid
9964642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
9974642e01fSmrg{
99835c4bbdfSmrg    RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
99905b261ecSmrg}
100005b261ecSmrg
100105b261ecSmrg/*
100205b261ecSmrg * Set the size of the gamma table at server startup time
100305b261ecSmrg */
100405b261ecSmrg
100505b261ecSmrgBool
100635c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
100705b261ecSmrg{
100835c4bbdfSmrg    CARD16 *gamma;
100905b261ecSmrg
101005b261ecSmrg    if (size == crtc->gammaSize)
101135c4bbdfSmrg        return TRUE;
101235c4bbdfSmrg    if (size) {
101335c4bbdfSmrg        gamma = xallocarray(size, 3 * sizeof(CARD16));
101435c4bbdfSmrg        if (!gamma)
101535c4bbdfSmrg            return FALSE;
101605b261ecSmrg    }
101705b261ecSmrg    else
101835c4bbdfSmrg        gamma = NULL;
10196747b715Smrg    free(crtc->gammaRed);
102005b261ecSmrg    crtc->gammaRed = gamma;
102105b261ecSmrg    crtc->gammaGreen = gamma + size;
102235c4bbdfSmrg    crtc->gammaBlue = gamma + size * 2;
102305b261ecSmrg    crtc->gammaSize = size;
102405b261ecSmrg    return TRUE;
102505b261ecSmrg}
102605b261ecSmrg
10274642e01fSmrg/*
10284642e01fSmrg * Set the pending CRTC transformation
10294642e01fSmrg */
10304642e01fSmrg
10314642e01fSmrgint
103235c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc,
103335c4bbdfSmrg                   PictTransformPtr transform,
103435c4bbdfSmrg                   struct pixman_f_transform *f_transform,
103535c4bbdfSmrg                   struct pixman_f_transform *f_inverse,
103635c4bbdfSmrg                   char *filter_name,
103735c4bbdfSmrg                   int filter_len, xFixed * params, int nparams)
10384642e01fSmrg{
103935c4bbdfSmrg    PictFilterPtr filter = NULL;
104035c4bbdfSmrg    int width = 0, height = 0;
10414642e01fSmrg
10424642e01fSmrg    if (!crtc->transforms)
104335c4bbdfSmrg        return BadValue;
104435c4bbdfSmrg
104535c4bbdfSmrg    if (filter_len) {
104635c4bbdfSmrg        filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
104735c4bbdfSmrg        if (!filter)
104835c4bbdfSmrg            return BadName;
104935c4bbdfSmrg        if (filter->ValidateParams) {
105035c4bbdfSmrg            if (!filter->ValidateParams(crtc->pScreen, filter->id,
105135c4bbdfSmrg                                        params, nparams, &width, &height))
105235c4bbdfSmrg                return BadMatch;
105335c4bbdfSmrg        }
105435c4bbdfSmrg        else {
105535c4bbdfSmrg            width = filter->width;
105635c4bbdfSmrg            height = filter->height;
105735c4bbdfSmrg        }
10584642e01fSmrg    }
105935c4bbdfSmrg    else {
106035c4bbdfSmrg        if (nparams)
106135c4bbdfSmrg            return BadMatch;
10624642e01fSmrg    }
106335c4bbdfSmrg    if (!RRTransformSetFilter(&crtc->client_pending_transform,
106435c4bbdfSmrg                              filter, params, nparams, width, height))
106535c4bbdfSmrg        return BadAlloc;
10664642e01fSmrg
10674642e01fSmrg    crtc->client_pending_transform.transform = *transform;
10684642e01fSmrg    crtc->client_pending_transform.f_transform = *f_transform;
10694642e01fSmrg    crtc->client_pending_transform.f_inverse = *f_inverse;
10704642e01fSmrg    return Success;
10714642e01fSmrg}
10724642e01fSmrg
107305b261ecSmrg/*
107405b261ecSmrg * Initialize crtc type
107505b261ecSmrg */
107605b261ecSmrgBool
107735c4bbdfSmrgRRCrtcInit(void)
107805b261ecSmrg{
107935c4bbdfSmrg    RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
108005b261ecSmrg    if (!RRCrtcType)
108135c4bbdfSmrg        return FALSE;
108235c4bbdfSmrg
108305b261ecSmrg    return TRUE;
108405b261ecSmrg}
108505b261ecSmrg
10866747b715Smrg/*
10876747b715Smrg * Initialize crtc type error value
10886747b715Smrg */
10896747b715Smrgvoid
10906747b715SmrgRRCrtcInitErrorValue(void)
10916747b715Smrg{
10926747b715Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
10936747b715Smrg}
10946747b715Smrg
109505b261ecSmrgint
109635c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client)
109705b261ecSmrg{
109805b261ecSmrg    REQUEST(xRRGetCrtcInfoReq);
109935c4bbdfSmrg    xRRGetCrtcInfoReply rep;
110035c4bbdfSmrg    RRCrtcPtr crtc;
11011b5d61b8Smrg    CARD8 *extra = NULL;
110235c4bbdfSmrg    unsigned long extraLen;
110335c4bbdfSmrg    ScreenPtr pScreen;
110435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
110535c4bbdfSmrg    RRModePtr mode;
110635c4bbdfSmrg    RROutput *outputs;
110735c4bbdfSmrg    RROutput *possible;
110835c4bbdfSmrg    int i, j, k;
110935c4bbdfSmrg    int width, height;
111035c4bbdfSmrg    BoxRec panned_area;
11111b5d61b8Smrg    Bool leased;
111235c4bbdfSmrg
111305b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
11146747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
111505b261ecSmrg
11161b5d61b8Smrg    leased = RRCrtcIsLeased(crtc);
11171b5d61b8Smrg
111805b261ecSmrg    /* All crtcs must be associated with screens before client
111905b261ecSmrg     * requests are processed
112005b261ecSmrg     */
112105b261ecSmrg    pScreen = crtc->pScreen;
112205b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
112305b261ecSmrg
112405b261ecSmrg    mode = crtc->mode;
112535c4bbdfSmrg
112635c4bbdfSmrg    rep = (xRRGetCrtcInfoReply) {
112735c4bbdfSmrg        .type = X_Reply,
112835c4bbdfSmrg        .status = RRSetConfigSuccess,
112935c4bbdfSmrg        .sequenceNumber = client->sequence,
113035c4bbdfSmrg        .length = 0,
113135c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
113235c4bbdfSmrg    };
11331b5d61b8Smrg    if (leased) {
11341b5d61b8Smrg        rep.x = rep.y = rep.width = rep.height = 0;
11351b5d61b8Smrg        rep.mode = 0;
11361b5d61b8Smrg        rep.rotation = RR_Rotate_0;
11371b5d61b8Smrg        rep.rotations = RR_Rotate_0;
11381b5d61b8Smrg        rep.nOutput = 0;
11391b5d61b8Smrg        rep.nPossibleOutput = 0;
11401b5d61b8Smrg        rep.length = 0;
11411b5d61b8Smrg        extraLen = 0;
11421b5d61b8Smrg    } else {
11431b5d61b8Smrg        if (pScrPriv->rrGetPanning &&
11441b5d61b8Smrg            pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
11451b5d61b8Smrg            (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
11461b5d61b8Smrg        {
11471b5d61b8Smrg            rep.x = panned_area.x1;
11481b5d61b8Smrg            rep.y = panned_area.y1;
11491b5d61b8Smrg            rep.width = panned_area.x2 - panned_area.x1;
11501b5d61b8Smrg            rep.height = panned_area.y2 - panned_area.y1;
11511b5d61b8Smrg        }
11521b5d61b8Smrg        else {
11531b5d61b8Smrg            RRCrtcGetScanoutSize(crtc, &width, &height);
11541b5d61b8Smrg            rep.x = crtc->x;
11551b5d61b8Smrg            rep.y = crtc->y;
11561b5d61b8Smrg            rep.width = width;
11571b5d61b8Smrg            rep.height = height;
11581b5d61b8Smrg        }
11591b5d61b8Smrg        rep.mode = mode ? mode->mode.id : 0;
11601b5d61b8Smrg        rep.rotation = crtc->rotation;
11611b5d61b8Smrg        rep.rotations = crtc->rotations;
11621b5d61b8Smrg        rep.nOutput = crtc->numOutputs;
11631b5d61b8Smrg        k = 0;
11641b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
11651b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
11661b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
11671b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
11681b5d61b8Smrg                        k++;
116935c4bbdfSmrg            }
11701b5d61b8Smrg        }
11711b5d61b8Smrg
11721b5d61b8Smrg        rep.nPossibleOutput = k;
11731b5d61b8Smrg
11741b5d61b8Smrg        rep.length = rep.nOutput + rep.nPossibleOutput;
11751b5d61b8Smrg
11761b5d61b8Smrg        extraLen = rep.length << 2;
11771b5d61b8Smrg        if (extraLen) {
11781b5d61b8Smrg            extra = malloc(extraLen);
11791b5d61b8Smrg            if (!extra)
11801b5d61b8Smrg                return BadAlloc;
11811b5d61b8Smrg        }
11821b5d61b8Smrg
11831b5d61b8Smrg        outputs = (RROutput *) extra;
11841b5d61b8Smrg        possible = (RROutput *) (outputs + rep.nOutput);
11851b5d61b8Smrg
11861b5d61b8Smrg        for (i = 0; i < crtc->numOutputs; i++) {
11871b5d61b8Smrg            outputs[i] = crtc->outputs[i]->id;
11881b5d61b8Smrg            if (client->swapped)
11891b5d61b8Smrg                swapl(&outputs[i]);
11901b5d61b8Smrg        }
11911b5d61b8Smrg        k = 0;
11921b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
11931b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
11941b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
11951b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
11961b5d61b8Smrg                        possible[k] = pScrPriv->outputs[i]->id;
11971b5d61b8Smrg                        if (client->swapped)
11981b5d61b8Smrg                            swapl(&possible[k]);
11991b5d61b8Smrg                        k++;
12001b5d61b8Smrg                    }
12011b5d61b8Smrg            }
12021b5d61b8Smrg        }
12031b5d61b8Smrg    }
120435c4bbdfSmrg
120505b261ecSmrg    if (client->swapped) {
120635c4bbdfSmrg        swaps(&rep.sequenceNumber);
120735c4bbdfSmrg        swapl(&rep.length);
120835c4bbdfSmrg        swapl(&rep.timestamp);
120935c4bbdfSmrg        swaps(&rep.x);
121035c4bbdfSmrg        swaps(&rep.y);
121135c4bbdfSmrg        swaps(&rep.width);
121235c4bbdfSmrg        swaps(&rep.height);
121335c4bbdfSmrg        swapl(&rep.mode);
121435c4bbdfSmrg        swaps(&rep.rotation);
121535c4bbdfSmrg        swaps(&rep.rotations);
121635c4bbdfSmrg        swaps(&rep.nOutput);
121735c4bbdfSmrg        swaps(&rep.nPossibleOutput);
121835c4bbdfSmrg    }
121935c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
122035c4bbdfSmrg    if (extraLen) {
122135c4bbdfSmrg        WriteToClient(client, extraLen, extra);
122235c4bbdfSmrg        free(extra);
122305b261ecSmrg    }
122435c4bbdfSmrg
12256747b715Smrg    return Success;
122605b261ecSmrg}
122705b261ecSmrg
122805b261ecSmrgint
122935c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client)
123005b261ecSmrg{
123105b261ecSmrg    REQUEST(xRRSetCrtcConfigReq);
123235c4bbdfSmrg    xRRSetCrtcConfigReply rep;
123335c4bbdfSmrg    ScreenPtr pScreen;
123435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
123535c4bbdfSmrg    RRCrtcPtr crtc;
123635c4bbdfSmrg    RRModePtr mode;
123735c4bbdfSmrg    int numOutputs;
123835c4bbdfSmrg    RROutputPtr *outputs = NULL;
123935c4bbdfSmrg    RROutput *outputIds;
124035c4bbdfSmrg    TimeStamp time;
124135c4bbdfSmrg    Rotation rotation;
124235c4bbdfSmrg    int ret, i, j;
124335c4bbdfSmrg    CARD8 status;
124435c4bbdfSmrg
124505b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
124635c4bbdfSmrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
124735c4bbdfSmrg
12486747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
12496747b715Smrg
12501b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
12511b5d61b8Smrg        return BadAccess;
12521b5d61b8Smrg
125335c4bbdfSmrg    if (stuff->mode == None) {
125435c4bbdfSmrg        mode = NULL;
125535c4bbdfSmrg        if (numOutputs > 0)
125635c4bbdfSmrg            return BadMatch;
125705b261ecSmrg    }
125835c4bbdfSmrg    else {
125935c4bbdfSmrg        VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
126035c4bbdfSmrg        if (numOutputs == 0)
126135c4bbdfSmrg            return BadMatch;
126205b261ecSmrg    }
126335c4bbdfSmrg    if (numOutputs) {
126435c4bbdfSmrg        outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
126535c4bbdfSmrg        if (!outputs)
126635c4bbdfSmrg            return BadAlloc;
126705b261ecSmrg    }
126805b261ecSmrg    else
126935c4bbdfSmrg        outputs = NULL;
127035c4bbdfSmrg
127105b261ecSmrg    outputIds = (RROutput *) (stuff + 1);
127235c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
127335c4bbdfSmrg        ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
127435c4bbdfSmrg                                     RROutputType, client, DixSetAttrAccess);
127535c4bbdfSmrg        if (ret != Success) {
127635c4bbdfSmrg            free(outputs);
127735c4bbdfSmrg            return ret;
127835c4bbdfSmrg        }
12791b5d61b8Smrg
12801b5d61b8Smrg        if (RROutputIsLeased(outputs[i])) {
12811b5d61b8Smrg            free(outputs);
12821b5d61b8Smrg            return BadAccess;
12831b5d61b8Smrg        }
12841b5d61b8Smrg
128535c4bbdfSmrg        /* validate crtc for this output */
128635c4bbdfSmrg        for (j = 0; j < outputs[i]->numCrtcs; j++)
128735c4bbdfSmrg            if (outputs[i]->crtcs[j] == crtc)
128835c4bbdfSmrg                break;
128935c4bbdfSmrg        if (j == outputs[i]->numCrtcs) {
129035c4bbdfSmrg            free(outputs);
129135c4bbdfSmrg            return BadMatch;
129235c4bbdfSmrg        }
129335c4bbdfSmrg        /* validate mode for this output */
129435c4bbdfSmrg        for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
129535c4bbdfSmrg            RRModePtr m = (j < outputs[i]->numModes ?
129635c4bbdfSmrg                           outputs[i]->modes[j] :
129735c4bbdfSmrg                           outputs[i]->userModes[j - outputs[i]->numModes]);
129835c4bbdfSmrg            if (m == mode)
129935c4bbdfSmrg                break;
130035c4bbdfSmrg        }
130135c4bbdfSmrg        if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
130235c4bbdfSmrg            free(outputs);
130335c4bbdfSmrg            return BadMatch;
130435c4bbdfSmrg        }
130505b261ecSmrg    }
130605b261ecSmrg    /* validate clones */
130735c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
130835c4bbdfSmrg        for (j = 0; j < numOutputs; j++) {
130935c4bbdfSmrg            int k;
131035c4bbdfSmrg
131135c4bbdfSmrg            if (i == j)
131235c4bbdfSmrg                continue;
131335c4bbdfSmrg            for (k = 0; k < outputs[i]->numClones; k++) {
131435c4bbdfSmrg                if (outputs[i]->clones[k] == outputs[j])
131535c4bbdfSmrg                    break;
131635c4bbdfSmrg            }
131735c4bbdfSmrg            if (k == outputs[i]->numClones) {
131835c4bbdfSmrg                free(outputs);
131935c4bbdfSmrg                return BadMatch;
132035c4bbdfSmrg            }
132135c4bbdfSmrg        }
132205b261ecSmrg    }
132305b261ecSmrg
132405b261ecSmrg    pScreen = crtc->pScreen;
132505b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
132635c4bbdfSmrg
132705b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
132835c4bbdfSmrg
132935c4bbdfSmrg    if (!pScrPriv) {
133035c4bbdfSmrg        time = currentTime;
133135c4bbdfSmrg        status = RRSetConfigFailed;
133235c4bbdfSmrg        goto sendReply;
133305b261ecSmrg    }
133435c4bbdfSmrg
133505b261ecSmrg    /*
133605b261ecSmrg     * Validate requested rotation
133705b261ecSmrg     */
133805b261ecSmrg    rotation = (Rotation) stuff->rotation;
133905b261ecSmrg
134005b261ecSmrg    /* test the rotation bits only! */
134105b261ecSmrg    switch (rotation & 0xf) {
134205b261ecSmrg    case RR_Rotate_0:
134305b261ecSmrg    case RR_Rotate_90:
134405b261ecSmrg    case RR_Rotate_180:
134505b261ecSmrg    case RR_Rotate_270:
134635c4bbdfSmrg        break;
134705b261ecSmrg    default:
134835c4bbdfSmrg        /*
134935c4bbdfSmrg         * Invalid rotation
135035c4bbdfSmrg         */
135135c4bbdfSmrg        client->errorValue = stuff->rotation;
135235c4bbdfSmrg        free(outputs);
135335c4bbdfSmrg        return BadValue;
135405b261ecSmrg    }
135505b261ecSmrg
135635c4bbdfSmrg    if (mode) {
135735c4bbdfSmrg        if ((~crtc->rotations) & rotation) {
135835c4bbdfSmrg            /*
135935c4bbdfSmrg             * requested rotation or reflection not supported by screen
136035c4bbdfSmrg             */
136135c4bbdfSmrg            client->errorValue = stuff->rotation;
136235c4bbdfSmrg            free(outputs);
136335c4bbdfSmrg            return BadMatch;
136435c4bbdfSmrg        }
136535c4bbdfSmrg
136605b261ecSmrg#ifdef RANDR_12_INTERFACE
136735c4bbdfSmrg        /*
136835c4bbdfSmrg         * Check screen size bounds if the DDX provides a 1.2 interface
136935c4bbdfSmrg         * for setting screen size. Else, assume the CrtcSet sets
137035c4bbdfSmrg         * the size along with the mode. If the driver supports transforms,
137135c4bbdfSmrg         * then it must allow crtcs to display a subset of the screen, so
137235c4bbdfSmrg         * only do this check for drivers without transform support.
137335c4bbdfSmrg         */
137435c4bbdfSmrg        if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
137535c4bbdfSmrg            int source_width;
137635c4bbdfSmrg            int source_height;
137735c4bbdfSmrg            PictTransform transform;
137835c4bbdfSmrg            struct pixman_f_transform f_transform, f_inverse;
137935c4bbdfSmrg            int width, height;
138035c4bbdfSmrg
138135c4bbdfSmrg            if (pScreen->isGPU) {
138235c4bbdfSmrg                width = pScreen->current_master->width;
138335c4bbdfSmrg                height = pScreen->current_master->height;
138435c4bbdfSmrg            }
138535c4bbdfSmrg            else {
138635c4bbdfSmrg                width = pScreen->width;
138735c4bbdfSmrg                height = pScreen->height;
138835c4bbdfSmrg            }
138935c4bbdfSmrg
139035c4bbdfSmrg            RRTransformCompute(stuff->x, stuff->y,
139135c4bbdfSmrg                               mode->mode.width, mode->mode.height,
139235c4bbdfSmrg                               rotation,
139335c4bbdfSmrg                               &crtc->client_pending_transform,
139435c4bbdfSmrg                               &transform, &f_transform, &f_inverse);
139535c4bbdfSmrg
139635c4bbdfSmrg            RRModeGetScanoutSize(mode, &transform, &source_width,
139735c4bbdfSmrg                                 &source_height);
139835c4bbdfSmrg            if (stuff->x + source_width > width) {
139935c4bbdfSmrg                client->errorValue = stuff->x;
140035c4bbdfSmrg                free(outputs);
140135c4bbdfSmrg                return BadValue;
140235c4bbdfSmrg            }
140335c4bbdfSmrg
140435c4bbdfSmrg            if (stuff->y + source_height > height) {
140535c4bbdfSmrg                client->errorValue = stuff->y;
140635c4bbdfSmrg                free(outputs);
140735c4bbdfSmrg                return BadValue;
140835c4bbdfSmrg            }
140935c4bbdfSmrg        }
141005b261ecSmrg#endif
141105b261ecSmrg    }
141235c4bbdfSmrg
141335c4bbdfSmrg    if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
141435c4bbdfSmrg                   rotation, numOutputs, outputs)) {
141535c4bbdfSmrg        status = RRSetConfigFailed;
141635c4bbdfSmrg        goto sendReply;
141705b261ecSmrg    }
141835c4bbdfSmrg    status = RRSetConfigSuccess;
141952397711Smrg    pScrPriv->lastSetTime = time;
142035c4bbdfSmrg
142135c4bbdfSmrg sendReply:
14226747b715Smrg    free(outputs);
142335c4bbdfSmrg
142435c4bbdfSmrg    rep = (xRRSetCrtcConfigReply) {
142535c4bbdfSmrg        .type = X_Reply,
142635c4bbdfSmrg        .status = status,
142735c4bbdfSmrg        .sequenceNumber = client->sequence,
142835c4bbdfSmrg        .length = 0,
142935c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
143035c4bbdfSmrg    };
143135c4bbdfSmrg
143235c4bbdfSmrg    if (client->swapped) {
143335c4bbdfSmrg        swaps(&rep.sequenceNumber);
143435c4bbdfSmrg        swapl(&rep.length);
143535c4bbdfSmrg        swapl(&rep.newTimestamp);
143605b261ecSmrg    }
143735c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
143835c4bbdfSmrg
14396747b715Smrg    return Success;
144005b261ecSmrg}
144105b261ecSmrg
14424642e01fSmrgint
144335c4bbdfSmrgProcRRGetPanning(ClientPtr client)
14444642e01fSmrg{
14454642e01fSmrg    REQUEST(xRRGetPanningReq);
144635c4bbdfSmrg    xRRGetPanningReply rep;
144735c4bbdfSmrg    RRCrtcPtr crtc;
144835c4bbdfSmrg    ScreenPtr pScreen;
144935c4bbdfSmrg    rrScrPrivPtr pScrPriv;
145035c4bbdfSmrg    BoxRec total;
145135c4bbdfSmrg    BoxRec tracking;
145235c4bbdfSmrg    INT16 border[4];
145335c4bbdfSmrg
14544642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
14556747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
14564642e01fSmrg
14574642e01fSmrg    /* All crtcs must be associated with screens before client
14584642e01fSmrg     * requests are processed
14594642e01fSmrg     */
14604642e01fSmrg    pScreen = crtc->pScreen;
14614642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
14624642e01fSmrg
14634642e01fSmrg    if (!pScrPriv)
146435c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
14654642e01fSmrg
146635c4bbdfSmrg    rep = (xRRGetPanningReply) {
146735c4bbdfSmrg        .type = X_Reply,
146835c4bbdfSmrg        .status = RRSetConfigSuccess,
146935c4bbdfSmrg        .sequenceNumber = client->sequence,
147035c4bbdfSmrg        .length = 1,
147135c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
147235c4bbdfSmrg    };
14734642e01fSmrg
14744642e01fSmrg    if (pScrPriv->rrGetPanning &&
147535c4bbdfSmrg        pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
147635c4bbdfSmrg        rep.left = total.x1;
147735c4bbdfSmrg        rep.top = total.y1;
147835c4bbdfSmrg        rep.width = total.x2 - total.x1;
147935c4bbdfSmrg        rep.height = total.y2 - total.y1;
148035c4bbdfSmrg        rep.track_left = tracking.x1;
148135c4bbdfSmrg        rep.track_top = tracking.y1;
148235c4bbdfSmrg        rep.track_width = tracking.x2 - tracking.x1;
148335c4bbdfSmrg        rep.track_height = tracking.y2 - tracking.y1;
148435c4bbdfSmrg        rep.border_left = border[0];
148535c4bbdfSmrg        rep.border_top = border[1];
148635c4bbdfSmrg        rep.border_right = border[2];
148735c4bbdfSmrg        rep.border_bottom = border[3];
14884642e01fSmrg    }
14894642e01fSmrg
14904642e01fSmrg    if (client->swapped) {
149135c4bbdfSmrg        swaps(&rep.sequenceNumber);
149235c4bbdfSmrg        swapl(&rep.length);
149335c4bbdfSmrg        swapl(&rep.timestamp);
149435c4bbdfSmrg        swaps(&rep.left);
149535c4bbdfSmrg        swaps(&rep.top);
149635c4bbdfSmrg        swaps(&rep.width);
149735c4bbdfSmrg        swaps(&rep.height);
149835c4bbdfSmrg        swaps(&rep.track_left);
149935c4bbdfSmrg        swaps(&rep.track_top);
150035c4bbdfSmrg        swaps(&rep.track_width);
150135c4bbdfSmrg        swaps(&rep.track_height);
150235c4bbdfSmrg        swaps(&rep.border_left);
150335c4bbdfSmrg        swaps(&rep.border_top);
150435c4bbdfSmrg        swaps(&rep.border_right);
150535c4bbdfSmrg        swaps(&rep.border_bottom);
150635c4bbdfSmrg    }
150735c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
15086747b715Smrg    return Success;
15094642e01fSmrg}
15104642e01fSmrg
15114642e01fSmrgint
151235c4bbdfSmrgProcRRSetPanning(ClientPtr client)
15134642e01fSmrg{
15144642e01fSmrg    REQUEST(xRRSetPanningReq);
151535c4bbdfSmrg    xRRSetPanningReply rep;
151635c4bbdfSmrg    RRCrtcPtr crtc;
151735c4bbdfSmrg    ScreenPtr pScreen;
151835c4bbdfSmrg    rrScrPrivPtr pScrPriv;
151935c4bbdfSmrg    TimeStamp time;
152035c4bbdfSmrg    BoxRec total;
152135c4bbdfSmrg    BoxRec tracking;
152235c4bbdfSmrg    INT16 border[4];
152335c4bbdfSmrg    CARD8 status;
152435c4bbdfSmrg
15254642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
15266747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15274642e01fSmrg
15281b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
15291b5d61b8Smrg        return BadAccess;
15301b5d61b8Smrg
15314642e01fSmrg    /* All crtcs must be associated with screens before client
15324642e01fSmrg     * requests are processed
15334642e01fSmrg     */
15344642e01fSmrg    pScreen = crtc->pScreen;
15354642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
15364642e01fSmrg
15374642e01fSmrg    if (!pScrPriv) {
153835c4bbdfSmrg        time = currentTime;
153935c4bbdfSmrg        status = RRSetConfigFailed;
154035c4bbdfSmrg        goto sendReply;
15414642e01fSmrg    }
154235c4bbdfSmrg
15434642e01fSmrg    time = ClientTimeToServerTime(stuff->timestamp);
154435c4bbdfSmrg
15454642e01fSmrg    if (!pScrPriv->rrGetPanning)
154635c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
15474642e01fSmrg
154835c4bbdfSmrg    total.x1 = stuff->left;
154935c4bbdfSmrg    total.y1 = stuff->top;
155035c4bbdfSmrg    total.x2 = total.x1 + stuff->width;
155135c4bbdfSmrg    total.y2 = total.y1 + stuff->height;
15524642e01fSmrg    tracking.x1 = stuff->track_left;
15534642e01fSmrg    tracking.y1 = stuff->track_top;
15544642e01fSmrg    tracking.x2 = tracking.x1 + stuff->track_width;
15554642e01fSmrg    tracking.y2 = tracking.y1 + stuff->track_height;
155635c4bbdfSmrg    border[0] = stuff->border_left;
155735c4bbdfSmrg    border[1] = stuff->border_top;
155835c4bbdfSmrg    border[2] = stuff->border_right;
155935c4bbdfSmrg    border[3] = stuff->border_bottom;
15604642e01fSmrg
156135c4bbdfSmrg    if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
156235c4bbdfSmrg        return BadMatch;
15634642e01fSmrg
156452397711Smrg    pScrPriv->lastSetTime = time;
156552397711Smrg
156635c4bbdfSmrg    status = RRSetConfigSuccess;
15674642e01fSmrg
156835c4bbdfSmrg sendReply:
156935c4bbdfSmrg    rep = (xRRSetPanningReply) {
157035c4bbdfSmrg        .type = X_Reply,
157135c4bbdfSmrg        .status = status,
157235c4bbdfSmrg        .sequenceNumber = client->sequence,
157335c4bbdfSmrg        .length = 0,
157435c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
157535c4bbdfSmrg    };
15764642e01fSmrg
15774642e01fSmrg    if (client->swapped) {
157835c4bbdfSmrg        swaps(&rep.sequenceNumber);
157935c4bbdfSmrg        swapl(&rep.length);
158035c4bbdfSmrg        swapl(&rep.newTimestamp);
15814642e01fSmrg    }
158235c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
15836747b715Smrg    return Success;
15844642e01fSmrg}
15854642e01fSmrg
158605b261ecSmrgint
158735c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client)
158805b261ecSmrg{
158905b261ecSmrg    REQUEST(xRRGetCrtcGammaSizeReq);
159035c4bbdfSmrg    xRRGetCrtcGammaSizeReply reply;
159135c4bbdfSmrg    RRCrtcPtr crtc;
159205b261ecSmrg
159305b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
15946747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15956747b715Smrg
15966747b715Smrg    /* Gamma retrieval failed, any better error? */
15976747b715Smrg    if (!RRCrtcGammaGet(crtc))
15986747b715Smrg        return RRErrorBase + BadRRCrtc;
15996747b715Smrg
160035c4bbdfSmrg    reply = (xRRGetCrtcGammaSizeReply) {
160135c4bbdfSmrg        .type = X_Reply,
160235c4bbdfSmrg        .sequenceNumber = client->sequence,
160335c4bbdfSmrg        .length = 0,
160435c4bbdfSmrg        .size = crtc->gammaSize
160535c4bbdfSmrg    };
160605b261ecSmrg    if (client->swapped) {
160735c4bbdfSmrg        swaps(&reply.sequenceNumber);
160835c4bbdfSmrg        swapl(&reply.length);
160935c4bbdfSmrg        swaps(&reply.size);
161005b261ecSmrg    }
161135c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
16126747b715Smrg    return Success;
161305b261ecSmrg}
161405b261ecSmrg
161505b261ecSmrgint
161635c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client)
161705b261ecSmrg{
161805b261ecSmrg    REQUEST(xRRGetCrtcGammaReq);
161935c4bbdfSmrg    xRRGetCrtcGammaReply reply;
162035c4bbdfSmrg    RRCrtcPtr crtc;
162135c4bbdfSmrg    unsigned long len;
162235c4bbdfSmrg    char *extra = NULL;
162335c4bbdfSmrg
162405b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
16256747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
16266747b715Smrg
16276747b715Smrg    /* Gamma retrieval failed, any better error? */
16286747b715Smrg    if (!RRCrtcGammaGet(crtc))
16296747b715Smrg        return RRErrorBase + BadRRCrtc;
16306747b715Smrg
163105b261ecSmrg    len = crtc->gammaSize * 3 * 2;
163235c4bbdfSmrg
16334642e01fSmrg    if (crtc->gammaSize) {
163435c4bbdfSmrg        extra = malloc(len);
163535c4bbdfSmrg        if (!extra)
163635c4bbdfSmrg            return BadAlloc;
16374642e01fSmrg    }
16384642e01fSmrg
163935c4bbdfSmrg    reply = (xRRGetCrtcGammaReply) {
164035c4bbdfSmrg        .type = X_Reply,
164135c4bbdfSmrg        .sequenceNumber = client->sequence,
164235c4bbdfSmrg        .length = bytes_to_int32(len),
164335c4bbdfSmrg        .size = crtc->gammaSize
164435c4bbdfSmrg    };
164505b261ecSmrg    if (client->swapped) {
164635c4bbdfSmrg        swaps(&reply.sequenceNumber);
164735c4bbdfSmrg        swapl(&reply.length);
164835c4bbdfSmrg        swaps(&reply.size);
164905b261ecSmrg    }
165035c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
165135c4bbdfSmrg    if (crtc->gammaSize) {
165235c4bbdfSmrg        memcpy(extra, crtc->gammaRed, len);
165335c4bbdfSmrg        client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
165435c4bbdfSmrg        WriteSwappedDataToClient(client, len, extra);
165535c4bbdfSmrg        free(extra);
165605b261ecSmrg    }
16576747b715Smrg    return Success;
165805b261ecSmrg}
165905b261ecSmrg
166005b261ecSmrgint
166135c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client)
166205b261ecSmrg{
166305b261ecSmrg    REQUEST(xRRSetCrtcGammaReq);
166435c4bbdfSmrg    RRCrtcPtr crtc;
166535c4bbdfSmrg    unsigned long len;
166635c4bbdfSmrg    CARD16 *red, *green, *blue;
166735c4bbdfSmrg
166805b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
16696747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
167035c4bbdfSmrg
16711b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
16721b5d61b8Smrg        return BadAccess;
16731b5d61b8Smrg
167435c4bbdfSmrg    len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
167505b261ecSmrg    if (len < (stuff->size * 3 + 1) >> 1)
167635c4bbdfSmrg        return BadLength;
167705b261ecSmrg
167805b261ecSmrg    if (stuff->size != crtc->gammaSize)
167935c4bbdfSmrg        return BadMatch;
168035c4bbdfSmrg
168105b261ecSmrg    red = (CARD16 *) (stuff + 1);
168205b261ecSmrg    green = red + crtc->gammaSize;
168305b261ecSmrg    blue = green + crtc->gammaSize;
168435c4bbdfSmrg
168535c4bbdfSmrg    RRCrtcGammaSet(crtc, red, green, blue);
168605b261ecSmrg
168705b261ecSmrg    return Success;
168805b261ecSmrg}
168905b261ecSmrg
16904642e01fSmrg/* Version 1.3 additions */
16914642e01fSmrg
16924642e01fSmrgint
169335c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client)
16944642e01fSmrg{
16954642e01fSmrg    REQUEST(xRRSetCrtcTransformReq);
169635c4bbdfSmrg    RRCrtcPtr crtc;
169735c4bbdfSmrg    PictTransform transform;
16984642e01fSmrg    struct pixman_f_transform f_transform, f_inverse;
169935c4bbdfSmrg    char *filter;
170035c4bbdfSmrg    int nbytes;
170135c4bbdfSmrg    xFixed *params;
170235c4bbdfSmrg    int nparams;
17034642e01fSmrg
17044642e01fSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
17056747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
17064642e01fSmrg
17071b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
17081b5d61b8Smrg        return BadAccess;
17091b5d61b8Smrg
171035c4bbdfSmrg    PictTransform_from_xRenderTransform(&transform, &stuff->transform);
171135c4bbdfSmrg    pixman_f_transform_from_pixman_transform(&f_transform, &transform);
171235c4bbdfSmrg    if (!pixman_f_transform_invert(&f_inverse, &f_transform))
171335c4bbdfSmrg        return BadMatch;
17144642e01fSmrg
17154642e01fSmrg    filter = (char *) (stuff + 1);
17164642e01fSmrg    nbytes = stuff->nbytesFilter;
17176747b715Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
17184642e01fSmrg    nparams = ((xFixed *) stuff + client->req_len) - params;
17194642e01fSmrg    if (nparams < 0)
172035c4bbdfSmrg        return BadLength;
17214642e01fSmrg
172235c4bbdfSmrg    return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
172335c4bbdfSmrg                              filter, nbytes, params, nparams);
17244642e01fSmrg}
17254642e01fSmrg
17264642e01fSmrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
172735c4bbdfSmrg
17284642e01fSmrgstatic int
172935c4bbdfSmrgtransform_filter_length(RRTransformPtr transform)
17304642e01fSmrg{
173135c4bbdfSmrg    int nbytes, nparams;
17324642e01fSmrg
17334642e01fSmrg    if (transform->filter == NULL)
173435c4bbdfSmrg        return 0;
173535c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17364642e01fSmrg    nparams = transform->nparams;
173735c4bbdfSmrg    return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
17384642e01fSmrg}
17394642e01fSmrg
17404642e01fSmrgstatic int
174135c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output,
174235c4bbdfSmrg                        CARD16 *nbytesFilter,
174335c4bbdfSmrg                        CARD16 *nparamsFilter, RRTransformPtr transform)
17444642e01fSmrg{
174535c4bbdfSmrg    int nbytes, nparams;
17464642e01fSmrg
17474642e01fSmrg    if (transform->filter == NULL) {
174835c4bbdfSmrg        *nbytesFilter = 0;
174935c4bbdfSmrg        *nparamsFilter = 0;
175035c4bbdfSmrg        return 0;
17514642e01fSmrg    }
175235c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17534642e01fSmrg    nparams = transform->nparams;
17544642e01fSmrg    *nbytesFilter = nbytes;
17554642e01fSmrg    *nparamsFilter = nparams;
175635c4bbdfSmrg    memcpy(output, transform->filter->name, nbytes);
17574642e01fSmrg    while ((nbytes & 3) != 0)
175835c4bbdfSmrg        output[nbytes++] = 0;
175935c4bbdfSmrg    memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
17604642e01fSmrg    if (client->swapped) {
176135c4bbdfSmrg        swaps(nbytesFilter);
176235c4bbdfSmrg        swaps(nparamsFilter);
176335c4bbdfSmrg        SwapLongs((CARD32 *) (output + nbytes), nparams);
17644642e01fSmrg    }
176535c4bbdfSmrg    nbytes += nparams * sizeof(xFixed);
17664642e01fSmrg    return nbytes;
17674642e01fSmrg}
17684642e01fSmrg
17694642e01fSmrgstatic void
177035c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire,
177135c4bbdfSmrg                 PictTransform * pict)
17724642e01fSmrg{
177335c4bbdfSmrg    xRenderTransform_from_PictTransform(wire, pict);
17744642e01fSmrg    if (client->swapped)
177535c4bbdfSmrg        SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
17764642e01fSmrg}
17774642e01fSmrg
17784642e01fSmrgint
177935c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client)
17804642e01fSmrg{
17814642e01fSmrg    REQUEST(xRRGetCrtcTransformReq);
178235c4bbdfSmrg    xRRGetCrtcTransformReply *reply;
178335c4bbdfSmrg    RRCrtcPtr crtc;
178435c4bbdfSmrg    int nextra;
178535c4bbdfSmrg    RRTransformPtr current, pending;
178635c4bbdfSmrg    char *extra;
17874642e01fSmrg
178835c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
17896747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
17904642e01fSmrg
17914642e01fSmrg    pending = &crtc->client_pending_transform;
17924642e01fSmrg    current = &crtc->client_current_transform;
17934642e01fSmrg
179435c4bbdfSmrg    nextra = (transform_filter_length(pending) +
179535c4bbdfSmrg              transform_filter_length(current));
17964642e01fSmrg
179735c4bbdfSmrg    reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
17984642e01fSmrg    if (!reply)
179935c4bbdfSmrg        return BadAlloc;
18004642e01fSmrg
18014642e01fSmrg    extra = (char *) (reply + 1);
18024642e01fSmrg    reply->type = X_Reply;
18034642e01fSmrg    reply->sequenceNumber = client->sequence;
18046747b715Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
18054642e01fSmrg
18064642e01fSmrg    reply->hasTransforms = crtc->transforms;
18074642e01fSmrg
180835c4bbdfSmrg    transform_encode(client, &reply->pendingTransform, &pending->transform);
180935c4bbdfSmrg    extra += transform_filter_encode(client, extra,
181035c4bbdfSmrg                                     &reply->pendingNbytesFilter,
181135c4bbdfSmrg                                     &reply->pendingNparamsFilter, pending);
18124642e01fSmrg
181335c4bbdfSmrg    transform_encode(client, &reply->currentTransform, &current->transform);
181435c4bbdfSmrg    extra += transform_filter_encode(client, extra,
181535c4bbdfSmrg                                     &reply->currentNbytesFilter,
181635c4bbdfSmrg                                     &reply->currentNparamsFilter, current);
18174642e01fSmrg
18184642e01fSmrg    if (client->swapped) {
181935c4bbdfSmrg        swaps(&reply->sequenceNumber);
182035c4bbdfSmrg        swapl(&reply->length);
18214642e01fSmrg    }
182235c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
18236747b715Smrg    free(reply);
18246747b715Smrg    return Success;
18254642e01fSmrg}
182635c4bbdfSmrg
182735c4bbdfSmrgstatic Bool
182835c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
182935c4bbdfSmrg{
183035c4bbdfSmrg    rrScrPriv(pScreen);
183135c4bbdfSmrg    int i;
183235c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
183335c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
183435c4bbdfSmrg
183535c4bbdfSmrg        int left, right, top, bottom;
183635c4bbdfSmrg
18371b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
18381b5d61b8Smrg	    continue;
183935c4bbdfSmrg
184035c4bbdfSmrg        if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
184135c4bbdfSmrg            return TRUE;
184235c4bbdfSmrg    }
184335c4bbdfSmrg    return FALSE;
184435c4bbdfSmrg}
184535c4bbdfSmrg
184635c4bbdfSmrgstatic Bool
184735c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
184835c4bbdfSmrg{
184935c4bbdfSmrg    rrScrPriv(pScreen);
185035c4bbdfSmrg    int i;
185135c4bbdfSmrg
185235c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
185335c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
185435c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
185535c4bbdfSmrg        int nx, ny;
185635c4bbdfSmrg        int left, right, top, bottom;
185735c4bbdfSmrg
18581b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
18591b5d61b8Smrg	    continue;
186035c4bbdfSmrg
186135c4bbdfSmrg        miPointerGetPosition(pDev, &nx, &ny);
186235c4bbdfSmrg
186335c4bbdfSmrg        if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
186435c4bbdfSmrg            if (*x < left)
186535c4bbdfSmrg                *x = left;
186635c4bbdfSmrg            if (*x >= right)
186735c4bbdfSmrg                *x = right - 1;
186835c4bbdfSmrg            if (*y < top)
186935c4bbdfSmrg                *y = top;
187035c4bbdfSmrg            if (*y >= bottom)
187135c4bbdfSmrg                *y = bottom - 1;
187235c4bbdfSmrg
187335c4bbdfSmrg            return TRUE;
187435c4bbdfSmrg        }
187535c4bbdfSmrg    }
187635c4bbdfSmrg    return FALSE;
187735c4bbdfSmrg}
187835c4bbdfSmrg
187935c4bbdfSmrgvoid
188035c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
188135c4bbdfSmrg                        int *y)
188235c4bbdfSmrg{
188335c4bbdfSmrg    rrScrPriv(pScreen);
188435c4bbdfSmrg    Bool ret;
188535c4bbdfSmrg    ScreenPtr slave;
188635c4bbdfSmrg
188735c4bbdfSmrg    /* intentional dead space -> let it float */
188835c4bbdfSmrg    if (pScrPriv->discontiguous)
188935c4bbdfSmrg        return;
189035c4bbdfSmrg
189135c4bbdfSmrg    /* if we're moving inside a crtc, we're fine */
189235c4bbdfSmrg    ret = check_all_screen_crtcs(pScreen, x, y);
189335c4bbdfSmrg    if (ret == TRUE)
189435c4bbdfSmrg        return;
189535c4bbdfSmrg
18961b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
18971b5d61b8Smrg        if (!slave->is_output_slave)
18981b5d61b8Smrg            continue;
18991b5d61b8Smrg
190035c4bbdfSmrg        ret = check_all_screen_crtcs(slave, x, y);
190135c4bbdfSmrg        if (ret == TRUE)
190235c4bbdfSmrg            return;
190335c4bbdfSmrg    }
190435c4bbdfSmrg
190535c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
190635c4bbdfSmrg    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
190735c4bbdfSmrg    if (ret == TRUE)
190835c4bbdfSmrg        return;
190935c4bbdfSmrg
19101b5d61b8Smrg    xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
19111b5d61b8Smrg        if (!slave->is_output_slave)
19121b5d61b8Smrg            continue;
19131b5d61b8Smrg
191435c4bbdfSmrg        ret = constrain_all_screen_crtcs(pDev, slave, x, y);
191535c4bbdfSmrg        if (ret == TRUE)
191635c4bbdfSmrg            return;
191735c4bbdfSmrg    }
191835c4bbdfSmrg}
191935c4bbdfSmrg
192035c4bbdfSmrgBool
192135c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
192235c4bbdfSmrg{
192335c4bbdfSmrg    rrScrPriv(pDrawable->pScreen);
192435c4bbdfSmrg    Bool ret = TRUE;
192535c4bbdfSmrg    PixmapPtr *saved_scanout_pixmap;
192635c4bbdfSmrg    int i;
192735c4bbdfSmrg
192835c4bbdfSmrg    saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
192935c4bbdfSmrg    if (saved_scanout_pixmap == NULL)
193035c4bbdfSmrg        return FALSE;
193135c4bbdfSmrg
193235c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
193335c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
193435c4bbdfSmrg        Bool size_fits;
193535c4bbdfSmrg
193635c4bbdfSmrg        saved_scanout_pixmap[i] = crtc->scanout_pixmap;
193735c4bbdfSmrg
193835c4bbdfSmrg        if (!crtc->mode && enable)
193935c4bbdfSmrg            continue;
194035c4bbdfSmrg        if (!crtc->scanout_pixmap && !enable)
194135c4bbdfSmrg            continue;
194235c4bbdfSmrg
19431b5d61b8Smrg        /* not supported with double buffering, needs ABI change for 2 ppix */
19441b5d61b8Smrg        if (crtc->scanout_pixmap_back) {
19451b5d61b8Smrg            ret = FALSE;
19461b5d61b8Smrg            continue;
19471b5d61b8Smrg        }
19481b5d61b8Smrg
194935c4bbdfSmrg        size_fits = (crtc->mode &&
195035c4bbdfSmrg                     crtc->x == pDrawable->x &&
195135c4bbdfSmrg                     crtc->y == pDrawable->y &&
195235c4bbdfSmrg                     crtc->mode->mode.width == pDrawable->width &&
195335c4bbdfSmrg                     crtc->mode->mode.height == pDrawable->height);
195435c4bbdfSmrg
195535c4bbdfSmrg        /* is the pixmap already set? */
195635c4bbdfSmrg        if (crtc->scanout_pixmap == pPixmap) {
195735c4bbdfSmrg            /* if its a disable then don't care about size */
195835c4bbdfSmrg            if (enable == FALSE) {
195935c4bbdfSmrg                /* set scanout to NULL */
196035c4bbdfSmrg                crtc->scanout_pixmap = NULL;
196135c4bbdfSmrg            }
196235c4bbdfSmrg            else if (!size_fits) {
196335c4bbdfSmrg                /* if the size no longer fits then drop off */
196435c4bbdfSmrg                crtc->scanout_pixmap = NULL;
196535c4bbdfSmrg                pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
196635c4bbdfSmrg
196735c4bbdfSmrg                (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
196835c4bbdfSmrg                                        crtc->rotation, crtc->numOutputs, crtc->outputs);
196935c4bbdfSmrg                saved_scanout_pixmap[i] = crtc->scanout_pixmap;
197035c4bbdfSmrg                ret = FALSE;
197135c4bbdfSmrg            }
197235c4bbdfSmrg            else {
197335c4bbdfSmrg                /* if the size fits then we are already setup */
197435c4bbdfSmrg            }
197535c4bbdfSmrg        }
197635c4bbdfSmrg        else {
197735c4bbdfSmrg            if (!size_fits)
197835c4bbdfSmrg                ret = FALSE;
197935c4bbdfSmrg            else if (enable)
198035c4bbdfSmrg                crtc->scanout_pixmap = pPixmap;
198135c4bbdfSmrg            else
198235c4bbdfSmrg                /* reject an attempt to disable someone else's scanout_pixmap */
198335c4bbdfSmrg                ret = FALSE;
198435c4bbdfSmrg        }
198535c4bbdfSmrg    }
198635c4bbdfSmrg
198735c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
198835c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
198935c4bbdfSmrg
199035c4bbdfSmrg        if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
199135c4bbdfSmrg            continue;
199235c4bbdfSmrg
199335c4bbdfSmrg        if (ret) {
199435c4bbdfSmrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
199535c4bbdfSmrg
199635c4bbdfSmrg            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
199735c4bbdfSmrg                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
199835c4bbdfSmrg        }
199935c4bbdfSmrg        else
200035c4bbdfSmrg            crtc->scanout_pixmap = saved_scanout_pixmap[i];
200135c4bbdfSmrg    }
200235c4bbdfSmrg    free(saved_scanout_pixmap);
200335c4bbdfSmrg
200435c4bbdfSmrg    return ret;
200535c4bbdfSmrg}
20061b5d61b8Smrg
20071b5d61b8SmrgBool
20081b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen)
20091b5d61b8Smrg{
20101b5d61b8Smrg    rrScrPriv(pScreen);
20111b5d61b8Smrg    int i;
20121b5d61b8Smrg
20131b5d61b8Smrg    if (!pScreen->is_output_slave)
20141b5d61b8Smrg        return FALSE;
20151b5d61b8Smrg
20161b5d61b8Smrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
20171b5d61b8Smrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
20181b5d61b8Smrg
20191b5d61b8Smrg        if (crtc->scanout_pixmap)
20201b5d61b8Smrg            return TRUE;
20211b5d61b8Smrg    }
20221b5d61b8Smrg
20231b5d61b8Smrg    return FALSE;
20241b5d61b8Smrg}
2025