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
30a035e2b2SmrgRESTYPE RRCrtcType = 0;
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) {
376ed6184dfSmrg    ScreenPtr primary = crtc->pScreen->current_primary;
37735c4bbdfSmrg
378ed6184dfSmrg    if (primary && pPixmap->primary_pixmap) {
37935c4bbdfSmrg        /*
38035c4bbdfSmrg         * Unref the pixmap twice: once for the original reference, and once
381ed6184dfSmrg         * for the reference implicitly added by PixmapShareToSecondary.
38235c4bbdfSmrg         */
383ed6184dfSmrg        PixmapUnshareSecondaryPixmap(pPixmap);
3841b5d61b8Smrg
385ed6184dfSmrg        primary->DestroyPixmap(pPixmap->primary_pixmap);
386ed6184dfSmrg        primary->DestroyPixmap(pPixmap->primary_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) {
398ed6184dfSmrg        ScreenPtr primary = crtc->pScreen->current_primary;
399ed6184dfSmrg        DrawablePtr mrootdraw = &primary->root->drawable;
40035c4bbdfSmrg
4011b5d61b8Smrg        if (crtc->scanout_pixmap_back) {
4021b5d61b8Smrg            pScrPriv->rrDisableSharedPixmapFlipping(crtc);
40335c4bbdfSmrg
40425da500fSmrg            if (mrootdraw) {
405ed6184dfSmrg                primary->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) {
417ed6184dfSmrg                primary->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
430ed6184dfSmrgrrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr primary,
4311b5d61b8Smrg                     int width, int height, int depth,
4321b5d61b8Smrg                     int x, int y, Rotation rotation)
4331b5d61b8Smrg{
4341b5d61b8Smrg    PixmapPtr mpix, spix;
4351b5d61b8Smrg
436ed6184dfSmrg    mpix = primary->CreatePixmap(primary, width, height, depth,
43735c4bbdfSmrg                                CREATE_PIXMAP_USAGE_SHARED);
43835c4bbdfSmrg    if (!mpix)
4391b5d61b8Smrg        return NULL;
44035c4bbdfSmrg
441ed6184dfSmrg    spix = PixmapShareToSecondary(mpix, crtc->pScreen);
44235c4bbdfSmrg    if (spix == NULL) {
443ed6184dfSmrg        primary->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{
505ed6184dfSmrg    ScreenPtr primary = crtc->pScreen->current_primary;
506ed6184dfSmrg    rrScrPrivPtr pPrimaryScrPriv = rrGetScrPriv(primary);
507ed6184dfSmrg    rrScrPrivPtr pSecondaryScrPriv = rrGetScrPriv(crtc->pScreen);
508ed6184dfSmrg    DrawablePtr mrootdraw = &primary->root->drawable;
5091b5d61b8Smrg    int depth = mrootdraw->depth;
5101b5d61b8Smrg    PixmapPtr spix_front;
5111b5d61b8Smrg
512ed6184dfSmrg    /* Create a pixmap on the primary screen, then get a shared handle for it.
513ed6184dfSmrg       Create a shared pixmap on the secondary screen using the handle.
5141b5d61b8Smrg
5151b5d61b8Smrg       If sync == FALSE --
516ed6184dfSmrg       Set secondary screen to scanout shared linear pixmap.
517ed6184dfSmrg       Set the primary 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.
522ed6184dfSmrg       Create another shared pixmap on the secondary screen using the handle.
523ed6184dfSmrg       Set secondary screen to prepare for scanout and flipping between shared
5241b5d61b8Smrg       linear pixmaps.
525ed6184dfSmrg       Set the primary screen to do dirty updates to the shared pixmaps from the
526ed6184dfSmrg       screen pixmap when prompted to by us or the secondary.
527ed6184dfSmrg       Prompt the primary to do a dirty update on the first shared pixmap, then
528ed6184dfSmrg       defer to the secondary.
5291b5d61b8Smrg    */
5301b5d61b8Smrg
5311b5d61b8Smrg    if (crtc->scanout_pixmap)
5321b5d61b8Smrg        RRCrtcDetachScanoutPixmap(crtc);
5331b5d61b8Smrg
5341b5d61b8Smrg    if (width == 0 && height == 0) {
5351b5d61b8Smrg        return TRUE;
5361b5d61b8Smrg    }
5371b5d61b8Smrg
538ed6184dfSmrg    spix_front = rrCreateSharedPixmap(crtc, primary,
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 &&
548ed6184dfSmrg        pSecondaryScrPriv->rrEnableSharedPixmapFlipping &&
549ed6184dfSmrg        pSecondaryScrPriv->rrDisableSharedPixmapFlipping &&
550ed6184dfSmrg        pPrimaryScrPriv->rrStartFlippingPixmapTracking &&
551ed6184dfSmrg        primary->PresentSharedPixmap &&
552ed6184dfSmrg        primary->StopFlippingPixmapTracking) {
5531b5d61b8Smrg
554ed6184dfSmrg        PixmapPtr spix_back = rrCreateSharedPixmap(crtc, primary,
5551b5d61b8Smrg                                                   width, height, depth,
5561b5d61b8Smrg                                                   x, y, rotation);
5571b5d61b8Smrg        if (spix_back == NULL)
5581b5d61b8Smrg            goto fail;
5591b5d61b8Smrg
560ed6184dfSmrg        if (!pSecondaryScrPriv->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
567ed6184dfSmrg        if (!pPrimaryScrPriv->rrStartFlippingPixmapTracking(crtc,
5681b5d61b8Smrg                                                           mrootdraw,
5691b5d61b8Smrg                                                           spix_front,
5701b5d61b8Smrg                                                           spix_back,
5711b5d61b8Smrg                                                           x, y, 0, 0,
5721b5d61b8Smrg                                                           rotation)) {
573ed6184dfSmrg            pSecondaryScrPriv->rrDisableSharedPixmapFlipping(crtc);
5741b5d61b8Smrg            goto fail;
5751b5d61b8Smrg        }
5761b5d61b8Smrg
577ed6184dfSmrg        primary->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
596ed6184dfSmrg    if (!pSecondaryScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
5971b5d61b8Smrg        rrDestroySharedPixmap(crtc, spix_front);
598ed6184dfSmrg        ErrorF("randr: failed to set shadow secondary pixmap\n");
59935c4bbdfSmrg        return FALSE;
60035c4bbdfSmrg    }
6011b5d61b8Smrg    crtc->scanout_pixmap = spix_front;
60235c4bbdfSmrg
603ed6184dfSmrg    primary->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;
636ed6184dfSmrg    ScreenPtr secondary;
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
644ed6184dfSmrg    /* have to iterate all the crtcs of the attached gpu primarys
645ed6184dfSmrg       and all their output secondarys */
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
669ed6184dfSmrg    xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
670ed6184dfSmrg        rrScrPrivPtr    secondary_priv = rrGetScrPriv(secondary);
6711b5d61b8Smrg
672ed6184dfSmrg        if (!secondary->is_output_secondary)
6731b5d61b8Smrg            continue;
6741b5d61b8Smrg
675ed6184dfSmrg        for (c = 0; c < secondary_priv->numCrtcs; c++) {
676ed6184dfSmrg            RRCrtcPtr secondary_crtc = secondary_priv->crtcs[c];
67735c4bbdfSmrg
678ed6184dfSmrg            if (secondary_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 {
691ed6184dfSmrg                if (!secondary_crtc->mode)
69235c4bbdfSmrg                    continue;
693ed6184dfSmrg                crtc_to_box(&newbox, secondary_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) {
759ed6184dfSmrg            ScreenPtr primary = pScreen->current_primary;
76035c4bbdfSmrg            int width = 0, height = 0;
76135c4bbdfSmrg
76235c4bbdfSmrg            if (mode) {
76335c4bbdfSmrg                width = mode->mode.width;
76435c4bbdfSmrg                height = mode->mode.height;
76535c4bbdfSmrg            }
766ed6184dfSmrg            ret = rrCheckPixmapBounding(primary, crtc,
76735c4bbdfSmrg                                        rotation, x, y, width, height);
76835c4bbdfSmrg            if (!ret)
76935c4bbdfSmrg                return FALSE;
77035c4bbdfSmrg
771ed6184dfSmrg            if (pScreen->current_primary) {
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
963a035e2b2Smrgstatic Bool RRCrtcInScreen(ScreenPtr pScreen, RRCrtcPtr findCrtc)
964a035e2b2Smrg{
965a035e2b2Smrg    rrScrPrivPtr pScrPriv;
966a035e2b2Smrg    int c;
967a035e2b2Smrg
968a035e2b2Smrg    if (pScreen == NULL)
969a035e2b2Smrg        return FALSE;
970a035e2b2Smrg
971a035e2b2Smrg    if (findCrtc == NULL)
972a035e2b2Smrg        return FALSE;
973a035e2b2Smrg
974a035e2b2Smrg    if (!dixPrivateKeyRegistered(rrPrivKey))
975a035e2b2Smrg        return FALSE;
976a035e2b2Smrg
977a035e2b2Smrg    pScrPriv = rrGetScrPriv(pScreen);
978a035e2b2Smrg    for (c = 0; c < pScrPriv->numCrtcs; c++) {
979a035e2b2Smrg        if (pScrPriv->crtcs[c] == findCrtc)
980a035e2b2Smrg            return TRUE;
981a035e2b2Smrg    }
982a035e2b2Smrg
983a035e2b2Smrg    return FALSE;
984a035e2b2Smrg}
985a035e2b2Smrg
986a035e2b2SmrgBool RRCrtcExists(ScreenPtr pScreen, RRCrtcPtr findCrtc)
987a035e2b2Smrg{
988ed6184dfSmrg    ScreenPtr secondary= NULL;
989a035e2b2Smrg
990a035e2b2Smrg    if (RRCrtcInScreen(pScreen, findCrtc))
991a035e2b2Smrg        return TRUE;
992a035e2b2Smrg
993ed6184dfSmrg    xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
994ed6184dfSmrg        if (!secondary->is_output_secondary)
995a035e2b2Smrg            continue;
996ed6184dfSmrg        if (RRCrtcInScreen(secondary, findCrtc))
997a035e2b2Smrg            return TRUE;
998a035e2b2Smrg    }
999a035e2b2Smrg
1000a035e2b2Smrg    return FALSE;
1001a035e2b2Smrg}
1002a035e2b2Smrg
1003a035e2b2Smrg
100405b261ecSmrg/*
100505b261ecSmrg * Notify the extension that the Crtc gamma has been changed
100605b261ecSmrg * The driver calls this whenever it has changed the gamma values
100705b261ecSmrg * in the RRCrtcRec
100805b261ecSmrg */
100905b261ecSmrg
101005b261ecSmrgBool
101135c4bbdfSmrgRRCrtcGammaNotify(RRCrtcPtr crtc)
101205b261ecSmrg{
101335c4bbdfSmrg    return TRUE;                /* not much going on here */
101405b261ecSmrg}
101505b261ecSmrg
10164642e01fSmrgstatic void
101735c4bbdfSmrgRRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
101835c4bbdfSmrg                     int *width, int *height)
101905b261ecSmrg{
102035c4bbdfSmrg    BoxRec box;
10214642e01fSmrg
10224642e01fSmrg    if (mode == NULL) {
102335c4bbdfSmrg        *width = 0;
102435c4bbdfSmrg        *height = 0;
102535c4bbdfSmrg        return;
102605b261ecSmrg    }
102705b261ecSmrg
10284642e01fSmrg    box.x1 = 0;
10294642e01fSmrg    box.y1 = 0;
10304642e01fSmrg    box.x2 = mode->mode.width;
10314642e01fSmrg    box.y2 = mode->mode.height;
10324642e01fSmrg
103335c4bbdfSmrg    pixman_transform_bounds(transform, &box);
10344642e01fSmrg    *width = box.x2 - box.x1;
10354642e01fSmrg    *height = box.y2 - box.y1;
10364642e01fSmrg}
10374642e01fSmrg
10384642e01fSmrg/**
10394642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer
10404642e01fSmrg */
10414642e01fSmrgvoid
10424642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
10434642e01fSmrg{
104435c4bbdfSmrg    RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
104505b261ecSmrg}
104605b261ecSmrg
104705b261ecSmrg/*
104805b261ecSmrg * Set the size of the gamma table at server startup time
104905b261ecSmrg */
105005b261ecSmrg
105105b261ecSmrgBool
105235c4bbdfSmrgRRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
105305b261ecSmrg{
105435c4bbdfSmrg    CARD16 *gamma;
105505b261ecSmrg
105605b261ecSmrg    if (size == crtc->gammaSize)
105735c4bbdfSmrg        return TRUE;
105835c4bbdfSmrg    if (size) {
105935c4bbdfSmrg        gamma = xallocarray(size, 3 * sizeof(CARD16));
106035c4bbdfSmrg        if (!gamma)
106135c4bbdfSmrg            return FALSE;
106205b261ecSmrg    }
106305b261ecSmrg    else
106435c4bbdfSmrg        gamma = NULL;
10656747b715Smrg    free(crtc->gammaRed);
106605b261ecSmrg    crtc->gammaRed = gamma;
106705b261ecSmrg    crtc->gammaGreen = gamma + size;
106835c4bbdfSmrg    crtc->gammaBlue = gamma + size * 2;
106905b261ecSmrg    crtc->gammaSize = size;
107005b261ecSmrg    return TRUE;
107105b261ecSmrg}
107205b261ecSmrg
10734642e01fSmrg/*
10744642e01fSmrg * Set the pending CRTC transformation
10754642e01fSmrg */
10764642e01fSmrg
10774642e01fSmrgint
107835c4bbdfSmrgRRCrtcTransformSet(RRCrtcPtr crtc,
107935c4bbdfSmrg                   PictTransformPtr transform,
108035c4bbdfSmrg                   struct pixman_f_transform *f_transform,
108135c4bbdfSmrg                   struct pixman_f_transform *f_inverse,
108235c4bbdfSmrg                   char *filter_name,
108335c4bbdfSmrg                   int filter_len, xFixed * params, int nparams)
10844642e01fSmrg{
108535c4bbdfSmrg    PictFilterPtr filter = NULL;
108635c4bbdfSmrg    int width = 0, height = 0;
10874642e01fSmrg
10884642e01fSmrg    if (!crtc->transforms)
108935c4bbdfSmrg        return BadValue;
109035c4bbdfSmrg
109135c4bbdfSmrg    if (filter_len) {
109235c4bbdfSmrg        filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
109335c4bbdfSmrg        if (!filter)
109435c4bbdfSmrg            return BadName;
109535c4bbdfSmrg        if (filter->ValidateParams) {
109635c4bbdfSmrg            if (!filter->ValidateParams(crtc->pScreen, filter->id,
109735c4bbdfSmrg                                        params, nparams, &width, &height))
109835c4bbdfSmrg                return BadMatch;
109935c4bbdfSmrg        }
110035c4bbdfSmrg        else {
110135c4bbdfSmrg            width = filter->width;
110235c4bbdfSmrg            height = filter->height;
110335c4bbdfSmrg        }
11044642e01fSmrg    }
110535c4bbdfSmrg    else {
110635c4bbdfSmrg        if (nparams)
110735c4bbdfSmrg            return BadMatch;
11084642e01fSmrg    }
110935c4bbdfSmrg    if (!RRTransformSetFilter(&crtc->client_pending_transform,
111035c4bbdfSmrg                              filter, params, nparams, width, height))
111135c4bbdfSmrg        return BadAlloc;
11124642e01fSmrg
11134642e01fSmrg    crtc->client_pending_transform.transform = *transform;
11144642e01fSmrg    crtc->client_pending_transform.f_transform = *f_transform;
11154642e01fSmrg    crtc->client_pending_transform.f_inverse = *f_inverse;
11164642e01fSmrg    return Success;
11174642e01fSmrg}
11184642e01fSmrg
111905b261ecSmrg/*
112005b261ecSmrg * Initialize crtc type
112105b261ecSmrg */
112205b261ecSmrgBool
112335c4bbdfSmrgRRCrtcInit(void)
112405b261ecSmrg{
112535c4bbdfSmrg    RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
112605b261ecSmrg    if (!RRCrtcType)
112735c4bbdfSmrg        return FALSE;
112835c4bbdfSmrg
112905b261ecSmrg    return TRUE;
113005b261ecSmrg}
113105b261ecSmrg
11326747b715Smrg/*
11336747b715Smrg * Initialize crtc type error value
11346747b715Smrg */
11356747b715Smrgvoid
11366747b715SmrgRRCrtcInitErrorValue(void)
11376747b715Smrg{
11386747b715Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
11396747b715Smrg}
11406747b715Smrg
114105b261ecSmrgint
114235c4bbdfSmrgProcRRGetCrtcInfo(ClientPtr client)
114305b261ecSmrg{
114405b261ecSmrg    REQUEST(xRRGetCrtcInfoReq);
114535c4bbdfSmrg    xRRGetCrtcInfoReply rep;
114635c4bbdfSmrg    RRCrtcPtr crtc;
11471b5d61b8Smrg    CARD8 *extra = NULL;
114835c4bbdfSmrg    unsigned long extraLen;
114935c4bbdfSmrg    ScreenPtr pScreen;
115035c4bbdfSmrg    rrScrPrivPtr pScrPriv;
115135c4bbdfSmrg    RRModePtr mode;
115235c4bbdfSmrg    RROutput *outputs;
115335c4bbdfSmrg    RROutput *possible;
115435c4bbdfSmrg    int i, j, k;
115535c4bbdfSmrg    int width, height;
115635c4bbdfSmrg    BoxRec panned_area;
11571b5d61b8Smrg    Bool leased;
115835c4bbdfSmrg
115905b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
11606747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
116105b261ecSmrg
11621b5d61b8Smrg    leased = RRCrtcIsLeased(crtc);
11631b5d61b8Smrg
116405b261ecSmrg    /* All crtcs must be associated with screens before client
116505b261ecSmrg     * requests are processed
116605b261ecSmrg     */
116705b261ecSmrg    pScreen = crtc->pScreen;
116805b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
116905b261ecSmrg
117005b261ecSmrg    mode = crtc->mode;
117135c4bbdfSmrg
117235c4bbdfSmrg    rep = (xRRGetCrtcInfoReply) {
117335c4bbdfSmrg        .type = X_Reply,
117435c4bbdfSmrg        .status = RRSetConfigSuccess,
117535c4bbdfSmrg        .sequenceNumber = client->sequence,
117635c4bbdfSmrg        .length = 0,
117735c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
117835c4bbdfSmrg    };
11791b5d61b8Smrg    if (leased) {
11801b5d61b8Smrg        rep.x = rep.y = rep.width = rep.height = 0;
11811b5d61b8Smrg        rep.mode = 0;
11821b5d61b8Smrg        rep.rotation = RR_Rotate_0;
11831b5d61b8Smrg        rep.rotations = RR_Rotate_0;
11841b5d61b8Smrg        rep.nOutput = 0;
11851b5d61b8Smrg        rep.nPossibleOutput = 0;
11861b5d61b8Smrg        rep.length = 0;
11871b5d61b8Smrg        extraLen = 0;
11881b5d61b8Smrg    } else {
11891b5d61b8Smrg        if (pScrPriv->rrGetPanning &&
11901b5d61b8Smrg            pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
11911b5d61b8Smrg            (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
11921b5d61b8Smrg        {
11931b5d61b8Smrg            rep.x = panned_area.x1;
11941b5d61b8Smrg            rep.y = panned_area.y1;
11951b5d61b8Smrg            rep.width = panned_area.x2 - panned_area.x1;
11961b5d61b8Smrg            rep.height = panned_area.y2 - panned_area.y1;
11971b5d61b8Smrg        }
11981b5d61b8Smrg        else {
11991b5d61b8Smrg            RRCrtcGetScanoutSize(crtc, &width, &height);
12001b5d61b8Smrg            rep.x = crtc->x;
12011b5d61b8Smrg            rep.y = crtc->y;
12021b5d61b8Smrg            rep.width = width;
12031b5d61b8Smrg            rep.height = height;
12041b5d61b8Smrg        }
12051b5d61b8Smrg        rep.mode = mode ? mode->mode.id : 0;
12061b5d61b8Smrg        rep.rotation = crtc->rotation;
12071b5d61b8Smrg        rep.rotations = crtc->rotations;
12081b5d61b8Smrg        rep.nOutput = crtc->numOutputs;
12091b5d61b8Smrg        k = 0;
12101b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
12111b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
12121b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
12131b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
12141b5d61b8Smrg                        k++;
121535c4bbdfSmrg            }
12161b5d61b8Smrg        }
12171b5d61b8Smrg
12181b5d61b8Smrg        rep.nPossibleOutput = k;
12191b5d61b8Smrg
12201b5d61b8Smrg        rep.length = rep.nOutput + rep.nPossibleOutput;
12211b5d61b8Smrg
12221b5d61b8Smrg        extraLen = rep.length << 2;
12231b5d61b8Smrg        if (extraLen) {
12241b5d61b8Smrg            extra = malloc(extraLen);
12251b5d61b8Smrg            if (!extra)
12261b5d61b8Smrg                return BadAlloc;
12271b5d61b8Smrg        }
12281b5d61b8Smrg
12291b5d61b8Smrg        outputs = (RROutput *) extra;
12301b5d61b8Smrg        possible = (RROutput *) (outputs + rep.nOutput);
12311b5d61b8Smrg
12321b5d61b8Smrg        for (i = 0; i < crtc->numOutputs; i++) {
12331b5d61b8Smrg            outputs[i] = crtc->outputs[i]->id;
12341b5d61b8Smrg            if (client->swapped)
12351b5d61b8Smrg                swapl(&outputs[i]);
12361b5d61b8Smrg        }
12371b5d61b8Smrg        k = 0;
12381b5d61b8Smrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
12391b5d61b8Smrg            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
12401b5d61b8Smrg                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
12411b5d61b8Smrg                    if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
12421b5d61b8Smrg                        possible[k] = pScrPriv->outputs[i]->id;
12431b5d61b8Smrg                        if (client->swapped)
12441b5d61b8Smrg                            swapl(&possible[k]);
12451b5d61b8Smrg                        k++;
12461b5d61b8Smrg                    }
12471b5d61b8Smrg            }
12481b5d61b8Smrg        }
12491b5d61b8Smrg    }
125035c4bbdfSmrg
125105b261ecSmrg    if (client->swapped) {
125235c4bbdfSmrg        swaps(&rep.sequenceNumber);
125335c4bbdfSmrg        swapl(&rep.length);
125435c4bbdfSmrg        swapl(&rep.timestamp);
125535c4bbdfSmrg        swaps(&rep.x);
125635c4bbdfSmrg        swaps(&rep.y);
125735c4bbdfSmrg        swaps(&rep.width);
125835c4bbdfSmrg        swaps(&rep.height);
125935c4bbdfSmrg        swapl(&rep.mode);
126035c4bbdfSmrg        swaps(&rep.rotation);
126135c4bbdfSmrg        swaps(&rep.rotations);
126235c4bbdfSmrg        swaps(&rep.nOutput);
126335c4bbdfSmrg        swaps(&rep.nPossibleOutput);
126435c4bbdfSmrg    }
126535c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
126635c4bbdfSmrg    if (extraLen) {
126735c4bbdfSmrg        WriteToClient(client, extraLen, extra);
126835c4bbdfSmrg        free(extra);
126905b261ecSmrg    }
127035c4bbdfSmrg
12716747b715Smrg    return Success;
127205b261ecSmrg}
127305b261ecSmrg
127405b261ecSmrgint
127535c4bbdfSmrgProcRRSetCrtcConfig(ClientPtr client)
127605b261ecSmrg{
127705b261ecSmrg    REQUEST(xRRSetCrtcConfigReq);
127835c4bbdfSmrg    xRRSetCrtcConfigReply rep;
127935c4bbdfSmrg    ScreenPtr pScreen;
128035c4bbdfSmrg    rrScrPrivPtr pScrPriv;
128135c4bbdfSmrg    RRCrtcPtr crtc;
128235c4bbdfSmrg    RRModePtr mode;
1283ed6184dfSmrg    unsigned int numOutputs;
128435c4bbdfSmrg    RROutputPtr *outputs = NULL;
128535c4bbdfSmrg    RROutput *outputIds;
128635c4bbdfSmrg    TimeStamp time;
128735c4bbdfSmrg    Rotation rotation;
128835c4bbdfSmrg    int ret, i, j;
128935c4bbdfSmrg    CARD8 status;
129035c4bbdfSmrg
129105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
129235c4bbdfSmrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
129335c4bbdfSmrg
12946747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
12956747b715Smrg
12961b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
12971b5d61b8Smrg        return BadAccess;
12981b5d61b8Smrg
129935c4bbdfSmrg    if (stuff->mode == None) {
130035c4bbdfSmrg        mode = NULL;
130135c4bbdfSmrg        if (numOutputs > 0)
130235c4bbdfSmrg            return BadMatch;
130305b261ecSmrg    }
130435c4bbdfSmrg    else {
130535c4bbdfSmrg        VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
130635c4bbdfSmrg        if (numOutputs == 0)
130735c4bbdfSmrg            return BadMatch;
130805b261ecSmrg    }
130935c4bbdfSmrg    if (numOutputs) {
131035c4bbdfSmrg        outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
131135c4bbdfSmrg        if (!outputs)
131235c4bbdfSmrg            return BadAlloc;
131305b261ecSmrg    }
131405b261ecSmrg    else
131535c4bbdfSmrg        outputs = NULL;
131635c4bbdfSmrg
131705b261ecSmrg    outputIds = (RROutput *) (stuff + 1);
131835c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
131935c4bbdfSmrg        ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
132035c4bbdfSmrg                                     RROutputType, client, DixSetAttrAccess);
132135c4bbdfSmrg        if (ret != Success) {
132235c4bbdfSmrg            free(outputs);
132335c4bbdfSmrg            return ret;
132435c4bbdfSmrg        }
13251b5d61b8Smrg
13261b5d61b8Smrg        if (RROutputIsLeased(outputs[i])) {
13271b5d61b8Smrg            free(outputs);
13281b5d61b8Smrg            return BadAccess;
13291b5d61b8Smrg        }
13301b5d61b8Smrg
133135c4bbdfSmrg        /* validate crtc for this output */
133235c4bbdfSmrg        for (j = 0; j < outputs[i]->numCrtcs; j++)
133335c4bbdfSmrg            if (outputs[i]->crtcs[j] == crtc)
133435c4bbdfSmrg                break;
133535c4bbdfSmrg        if (j == outputs[i]->numCrtcs) {
133635c4bbdfSmrg            free(outputs);
133735c4bbdfSmrg            return BadMatch;
133835c4bbdfSmrg        }
133935c4bbdfSmrg        /* validate mode for this output */
134035c4bbdfSmrg        for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
134135c4bbdfSmrg            RRModePtr m = (j < outputs[i]->numModes ?
134235c4bbdfSmrg                           outputs[i]->modes[j] :
134335c4bbdfSmrg                           outputs[i]->userModes[j - outputs[i]->numModes]);
134435c4bbdfSmrg            if (m == mode)
134535c4bbdfSmrg                break;
134635c4bbdfSmrg        }
134735c4bbdfSmrg        if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
134835c4bbdfSmrg            free(outputs);
134935c4bbdfSmrg            return BadMatch;
135035c4bbdfSmrg        }
135105b261ecSmrg    }
135205b261ecSmrg    /* validate clones */
135335c4bbdfSmrg    for (i = 0; i < numOutputs; i++) {
135435c4bbdfSmrg        for (j = 0; j < numOutputs; j++) {
135535c4bbdfSmrg            int k;
135635c4bbdfSmrg
135735c4bbdfSmrg            if (i == j)
135835c4bbdfSmrg                continue;
135935c4bbdfSmrg            for (k = 0; k < outputs[i]->numClones; k++) {
136035c4bbdfSmrg                if (outputs[i]->clones[k] == outputs[j])
136135c4bbdfSmrg                    break;
136235c4bbdfSmrg            }
136335c4bbdfSmrg            if (k == outputs[i]->numClones) {
136435c4bbdfSmrg                free(outputs);
136535c4bbdfSmrg                return BadMatch;
136635c4bbdfSmrg            }
136735c4bbdfSmrg        }
136805b261ecSmrg    }
136905b261ecSmrg
137005b261ecSmrg    pScreen = crtc->pScreen;
137105b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
137235c4bbdfSmrg
137305b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
137435c4bbdfSmrg
137535c4bbdfSmrg    if (!pScrPriv) {
137635c4bbdfSmrg        time = currentTime;
137735c4bbdfSmrg        status = RRSetConfigFailed;
137835c4bbdfSmrg        goto sendReply;
137905b261ecSmrg    }
138035c4bbdfSmrg
138105b261ecSmrg    /*
138205b261ecSmrg     * Validate requested rotation
138305b261ecSmrg     */
138405b261ecSmrg    rotation = (Rotation) stuff->rotation;
138505b261ecSmrg
138605b261ecSmrg    /* test the rotation bits only! */
138705b261ecSmrg    switch (rotation & 0xf) {
138805b261ecSmrg    case RR_Rotate_0:
138905b261ecSmrg    case RR_Rotate_90:
139005b261ecSmrg    case RR_Rotate_180:
139105b261ecSmrg    case RR_Rotate_270:
139235c4bbdfSmrg        break;
139305b261ecSmrg    default:
139435c4bbdfSmrg        /*
139535c4bbdfSmrg         * Invalid rotation
139635c4bbdfSmrg         */
139735c4bbdfSmrg        client->errorValue = stuff->rotation;
139835c4bbdfSmrg        free(outputs);
139935c4bbdfSmrg        return BadValue;
140005b261ecSmrg    }
140105b261ecSmrg
140235c4bbdfSmrg    if (mode) {
140335c4bbdfSmrg        if ((~crtc->rotations) & rotation) {
140435c4bbdfSmrg            /*
140535c4bbdfSmrg             * requested rotation or reflection not supported by screen
140635c4bbdfSmrg             */
140735c4bbdfSmrg            client->errorValue = stuff->rotation;
140835c4bbdfSmrg            free(outputs);
140935c4bbdfSmrg            return BadMatch;
141035c4bbdfSmrg        }
141135c4bbdfSmrg
141205b261ecSmrg#ifdef RANDR_12_INTERFACE
141335c4bbdfSmrg        /*
141435c4bbdfSmrg         * Check screen size bounds if the DDX provides a 1.2 interface
141535c4bbdfSmrg         * for setting screen size. Else, assume the CrtcSet sets
141635c4bbdfSmrg         * the size along with the mode. If the driver supports transforms,
141735c4bbdfSmrg         * then it must allow crtcs to display a subset of the screen, so
141835c4bbdfSmrg         * only do this check for drivers without transform support.
141935c4bbdfSmrg         */
142035c4bbdfSmrg        if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
142135c4bbdfSmrg            int source_width;
142235c4bbdfSmrg            int source_height;
142335c4bbdfSmrg            PictTransform transform;
142435c4bbdfSmrg            struct pixman_f_transform f_transform, f_inverse;
142535c4bbdfSmrg            int width, height;
142635c4bbdfSmrg
142735c4bbdfSmrg            if (pScreen->isGPU) {
1428ed6184dfSmrg                width = pScreen->current_primary->width;
1429ed6184dfSmrg                height = pScreen->current_primary->height;
143035c4bbdfSmrg            }
143135c4bbdfSmrg            else {
143235c4bbdfSmrg                width = pScreen->width;
143335c4bbdfSmrg                height = pScreen->height;
143435c4bbdfSmrg            }
143535c4bbdfSmrg
143635c4bbdfSmrg            RRTransformCompute(stuff->x, stuff->y,
143735c4bbdfSmrg                               mode->mode.width, mode->mode.height,
143835c4bbdfSmrg                               rotation,
143935c4bbdfSmrg                               &crtc->client_pending_transform,
144035c4bbdfSmrg                               &transform, &f_transform, &f_inverse);
144135c4bbdfSmrg
144235c4bbdfSmrg            RRModeGetScanoutSize(mode, &transform, &source_width,
144335c4bbdfSmrg                                 &source_height);
144435c4bbdfSmrg            if (stuff->x + source_width > width) {
144535c4bbdfSmrg                client->errorValue = stuff->x;
144635c4bbdfSmrg                free(outputs);
144735c4bbdfSmrg                return BadValue;
144835c4bbdfSmrg            }
144935c4bbdfSmrg
145035c4bbdfSmrg            if (stuff->y + source_height > height) {
145135c4bbdfSmrg                client->errorValue = stuff->y;
145235c4bbdfSmrg                free(outputs);
145335c4bbdfSmrg                return BadValue;
145435c4bbdfSmrg            }
145535c4bbdfSmrg        }
145605b261ecSmrg#endif
145705b261ecSmrg    }
145835c4bbdfSmrg
145935c4bbdfSmrg    if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
146035c4bbdfSmrg                   rotation, numOutputs, outputs)) {
146135c4bbdfSmrg        status = RRSetConfigFailed;
146235c4bbdfSmrg        goto sendReply;
146305b261ecSmrg    }
146435c4bbdfSmrg    status = RRSetConfigSuccess;
146552397711Smrg    pScrPriv->lastSetTime = time;
146635c4bbdfSmrg
146735c4bbdfSmrg sendReply:
14686747b715Smrg    free(outputs);
146935c4bbdfSmrg
147035c4bbdfSmrg    rep = (xRRSetCrtcConfigReply) {
147135c4bbdfSmrg        .type = X_Reply,
147235c4bbdfSmrg        .status = status,
147335c4bbdfSmrg        .sequenceNumber = client->sequence,
147435c4bbdfSmrg        .length = 0,
147535c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
147635c4bbdfSmrg    };
147735c4bbdfSmrg
147835c4bbdfSmrg    if (client->swapped) {
147935c4bbdfSmrg        swaps(&rep.sequenceNumber);
148035c4bbdfSmrg        swapl(&rep.length);
148135c4bbdfSmrg        swapl(&rep.newTimestamp);
148205b261ecSmrg    }
148335c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
148435c4bbdfSmrg
14856747b715Smrg    return Success;
148605b261ecSmrg}
148705b261ecSmrg
14884642e01fSmrgint
148935c4bbdfSmrgProcRRGetPanning(ClientPtr client)
14904642e01fSmrg{
14914642e01fSmrg    REQUEST(xRRGetPanningReq);
149235c4bbdfSmrg    xRRGetPanningReply rep;
149335c4bbdfSmrg    RRCrtcPtr crtc;
149435c4bbdfSmrg    ScreenPtr pScreen;
149535c4bbdfSmrg    rrScrPrivPtr pScrPriv;
149635c4bbdfSmrg    BoxRec total;
149735c4bbdfSmrg    BoxRec tracking;
149835c4bbdfSmrg    INT16 border[4];
149935c4bbdfSmrg
15004642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
15016747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15024642e01fSmrg
15034642e01fSmrg    /* All crtcs must be associated with screens before client
15044642e01fSmrg     * requests are processed
15054642e01fSmrg     */
15064642e01fSmrg    pScreen = crtc->pScreen;
15074642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
15084642e01fSmrg
15094642e01fSmrg    if (!pScrPriv)
151035c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
15114642e01fSmrg
151235c4bbdfSmrg    rep = (xRRGetPanningReply) {
151335c4bbdfSmrg        .type = X_Reply,
151435c4bbdfSmrg        .status = RRSetConfigSuccess,
151535c4bbdfSmrg        .sequenceNumber = client->sequence,
151635c4bbdfSmrg        .length = 1,
151735c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds
151835c4bbdfSmrg    };
15194642e01fSmrg
15204642e01fSmrg    if (pScrPriv->rrGetPanning &&
152135c4bbdfSmrg        pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
152235c4bbdfSmrg        rep.left = total.x1;
152335c4bbdfSmrg        rep.top = total.y1;
152435c4bbdfSmrg        rep.width = total.x2 - total.x1;
152535c4bbdfSmrg        rep.height = total.y2 - total.y1;
152635c4bbdfSmrg        rep.track_left = tracking.x1;
152735c4bbdfSmrg        rep.track_top = tracking.y1;
152835c4bbdfSmrg        rep.track_width = tracking.x2 - tracking.x1;
152935c4bbdfSmrg        rep.track_height = tracking.y2 - tracking.y1;
153035c4bbdfSmrg        rep.border_left = border[0];
153135c4bbdfSmrg        rep.border_top = border[1];
153235c4bbdfSmrg        rep.border_right = border[2];
153335c4bbdfSmrg        rep.border_bottom = border[3];
15344642e01fSmrg    }
15354642e01fSmrg
15364642e01fSmrg    if (client->swapped) {
153735c4bbdfSmrg        swaps(&rep.sequenceNumber);
153835c4bbdfSmrg        swapl(&rep.length);
153935c4bbdfSmrg        swapl(&rep.timestamp);
154035c4bbdfSmrg        swaps(&rep.left);
154135c4bbdfSmrg        swaps(&rep.top);
154235c4bbdfSmrg        swaps(&rep.width);
154335c4bbdfSmrg        swaps(&rep.height);
154435c4bbdfSmrg        swaps(&rep.track_left);
154535c4bbdfSmrg        swaps(&rep.track_top);
154635c4bbdfSmrg        swaps(&rep.track_width);
154735c4bbdfSmrg        swaps(&rep.track_height);
154835c4bbdfSmrg        swaps(&rep.border_left);
154935c4bbdfSmrg        swaps(&rep.border_top);
155035c4bbdfSmrg        swaps(&rep.border_right);
155135c4bbdfSmrg        swaps(&rep.border_bottom);
155235c4bbdfSmrg    }
155335c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
15546747b715Smrg    return Success;
15554642e01fSmrg}
15564642e01fSmrg
15574642e01fSmrgint
155835c4bbdfSmrgProcRRSetPanning(ClientPtr client)
15594642e01fSmrg{
15604642e01fSmrg    REQUEST(xRRSetPanningReq);
156135c4bbdfSmrg    xRRSetPanningReply rep;
156235c4bbdfSmrg    RRCrtcPtr crtc;
156335c4bbdfSmrg    ScreenPtr pScreen;
156435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
156535c4bbdfSmrg    TimeStamp time;
156635c4bbdfSmrg    BoxRec total;
156735c4bbdfSmrg    BoxRec tracking;
156835c4bbdfSmrg    INT16 border[4];
156935c4bbdfSmrg    CARD8 status;
157035c4bbdfSmrg
15714642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
15726747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
15734642e01fSmrg
15741b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
15751b5d61b8Smrg        return BadAccess;
15761b5d61b8Smrg
15774642e01fSmrg    /* All crtcs must be associated with screens before client
15784642e01fSmrg     * requests are processed
15794642e01fSmrg     */
15804642e01fSmrg    pScreen = crtc->pScreen;
15814642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
15824642e01fSmrg
15834642e01fSmrg    if (!pScrPriv) {
158435c4bbdfSmrg        time = currentTime;
158535c4bbdfSmrg        status = RRSetConfigFailed;
158635c4bbdfSmrg        goto sendReply;
15874642e01fSmrg    }
158835c4bbdfSmrg
15894642e01fSmrg    time = ClientTimeToServerTime(stuff->timestamp);
159035c4bbdfSmrg
15914642e01fSmrg    if (!pScrPriv->rrGetPanning)
159235c4bbdfSmrg        return RRErrorBase + BadRRCrtc;
15934642e01fSmrg
159435c4bbdfSmrg    total.x1 = stuff->left;
159535c4bbdfSmrg    total.y1 = stuff->top;
159635c4bbdfSmrg    total.x2 = total.x1 + stuff->width;
159735c4bbdfSmrg    total.y2 = total.y1 + stuff->height;
15984642e01fSmrg    tracking.x1 = stuff->track_left;
15994642e01fSmrg    tracking.y1 = stuff->track_top;
16004642e01fSmrg    tracking.x2 = tracking.x1 + stuff->track_width;
16014642e01fSmrg    tracking.y2 = tracking.y1 + stuff->track_height;
160235c4bbdfSmrg    border[0] = stuff->border_left;
160335c4bbdfSmrg    border[1] = stuff->border_top;
160435c4bbdfSmrg    border[2] = stuff->border_right;
160535c4bbdfSmrg    border[3] = stuff->border_bottom;
16064642e01fSmrg
160735c4bbdfSmrg    if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
160835c4bbdfSmrg        return BadMatch;
16094642e01fSmrg
161052397711Smrg    pScrPriv->lastSetTime = time;
161152397711Smrg
161235c4bbdfSmrg    status = RRSetConfigSuccess;
16134642e01fSmrg
161435c4bbdfSmrg sendReply:
161535c4bbdfSmrg    rep = (xRRSetPanningReply) {
161635c4bbdfSmrg        .type = X_Reply,
161735c4bbdfSmrg        .status = status,
161835c4bbdfSmrg        .sequenceNumber = client->sequence,
161935c4bbdfSmrg        .length = 0,
162035c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds
162135c4bbdfSmrg    };
16224642e01fSmrg
16234642e01fSmrg    if (client->swapped) {
162435c4bbdfSmrg        swaps(&rep.sequenceNumber);
162535c4bbdfSmrg        swapl(&rep.length);
162635c4bbdfSmrg        swapl(&rep.newTimestamp);
16274642e01fSmrg    }
162835c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
16296747b715Smrg    return Success;
16304642e01fSmrg}
16314642e01fSmrg
163205b261ecSmrgint
163335c4bbdfSmrgProcRRGetCrtcGammaSize(ClientPtr client)
163405b261ecSmrg{
163505b261ecSmrg    REQUEST(xRRGetCrtcGammaSizeReq);
163635c4bbdfSmrg    xRRGetCrtcGammaSizeReply reply;
163735c4bbdfSmrg    RRCrtcPtr crtc;
163805b261ecSmrg
163905b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
16406747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
16416747b715Smrg
16426747b715Smrg    /* Gamma retrieval failed, any better error? */
16436747b715Smrg    if (!RRCrtcGammaGet(crtc))
16446747b715Smrg        return RRErrorBase + BadRRCrtc;
16456747b715Smrg
164635c4bbdfSmrg    reply = (xRRGetCrtcGammaSizeReply) {
164735c4bbdfSmrg        .type = X_Reply,
164835c4bbdfSmrg        .sequenceNumber = client->sequence,
164935c4bbdfSmrg        .length = 0,
165035c4bbdfSmrg        .size = crtc->gammaSize
165135c4bbdfSmrg    };
165205b261ecSmrg    if (client->swapped) {
165335c4bbdfSmrg        swaps(&reply.sequenceNumber);
165435c4bbdfSmrg        swapl(&reply.length);
165535c4bbdfSmrg        swaps(&reply.size);
165605b261ecSmrg    }
165735c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
16586747b715Smrg    return Success;
165905b261ecSmrg}
166005b261ecSmrg
166105b261ecSmrgint
166235c4bbdfSmrgProcRRGetCrtcGamma(ClientPtr client)
166305b261ecSmrg{
166405b261ecSmrg    REQUEST(xRRGetCrtcGammaReq);
166535c4bbdfSmrg    xRRGetCrtcGammaReply reply;
166635c4bbdfSmrg    RRCrtcPtr crtc;
166735c4bbdfSmrg    unsigned long len;
166835c4bbdfSmrg    char *extra = NULL;
166935c4bbdfSmrg
167005b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
16716747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
16726747b715Smrg
16736747b715Smrg    /* Gamma retrieval failed, any better error? */
16746747b715Smrg    if (!RRCrtcGammaGet(crtc))
16756747b715Smrg        return RRErrorBase + BadRRCrtc;
16766747b715Smrg
167705b261ecSmrg    len = crtc->gammaSize * 3 * 2;
167835c4bbdfSmrg
16794642e01fSmrg    if (crtc->gammaSize) {
168035c4bbdfSmrg        extra = malloc(len);
168135c4bbdfSmrg        if (!extra)
168235c4bbdfSmrg            return BadAlloc;
16834642e01fSmrg    }
16844642e01fSmrg
168535c4bbdfSmrg    reply = (xRRGetCrtcGammaReply) {
168635c4bbdfSmrg        .type = X_Reply,
168735c4bbdfSmrg        .sequenceNumber = client->sequence,
168835c4bbdfSmrg        .length = bytes_to_int32(len),
168935c4bbdfSmrg        .size = crtc->gammaSize
169035c4bbdfSmrg    };
169105b261ecSmrg    if (client->swapped) {
169235c4bbdfSmrg        swaps(&reply.sequenceNumber);
169335c4bbdfSmrg        swapl(&reply.length);
169435c4bbdfSmrg        swaps(&reply.size);
169505b261ecSmrg    }
169635c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
169735c4bbdfSmrg    if (crtc->gammaSize) {
169835c4bbdfSmrg        memcpy(extra, crtc->gammaRed, len);
169935c4bbdfSmrg        client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
170035c4bbdfSmrg        WriteSwappedDataToClient(client, len, extra);
170135c4bbdfSmrg        free(extra);
170205b261ecSmrg    }
17036747b715Smrg    return Success;
170405b261ecSmrg}
170505b261ecSmrg
170605b261ecSmrgint
170735c4bbdfSmrgProcRRSetCrtcGamma(ClientPtr client)
170805b261ecSmrg{
170905b261ecSmrg    REQUEST(xRRSetCrtcGammaReq);
171035c4bbdfSmrg    RRCrtcPtr crtc;
171135c4bbdfSmrg    unsigned long len;
171235c4bbdfSmrg    CARD16 *red, *green, *blue;
171335c4bbdfSmrg
171405b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
17156747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
171635c4bbdfSmrg
17171b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
17181b5d61b8Smrg        return BadAccess;
17191b5d61b8Smrg
172035c4bbdfSmrg    len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
172105b261ecSmrg    if (len < (stuff->size * 3 + 1) >> 1)
172235c4bbdfSmrg        return BadLength;
172305b261ecSmrg
172405b261ecSmrg    if (stuff->size != crtc->gammaSize)
172535c4bbdfSmrg        return BadMatch;
172635c4bbdfSmrg
172705b261ecSmrg    red = (CARD16 *) (stuff + 1);
172805b261ecSmrg    green = red + crtc->gammaSize;
172905b261ecSmrg    blue = green + crtc->gammaSize;
173035c4bbdfSmrg
173135c4bbdfSmrg    RRCrtcGammaSet(crtc, red, green, blue);
173205b261ecSmrg
173305b261ecSmrg    return Success;
173405b261ecSmrg}
173505b261ecSmrg
17364642e01fSmrg/* Version 1.3 additions */
17374642e01fSmrg
17384642e01fSmrgint
173935c4bbdfSmrgProcRRSetCrtcTransform(ClientPtr client)
17404642e01fSmrg{
17414642e01fSmrg    REQUEST(xRRSetCrtcTransformReq);
174235c4bbdfSmrg    RRCrtcPtr crtc;
174335c4bbdfSmrg    PictTransform transform;
17444642e01fSmrg    struct pixman_f_transform f_transform, f_inverse;
174535c4bbdfSmrg    char *filter;
174635c4bbdfSmrg    int nbytes;
174735c4bbdfSmrg    xFixed *params;
174835c4bbdfSmrg    int nparams;
17494642e01fSmrg
17504642e01fSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
17516747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
17524642e01fSmrg
17531b5d61b8Smrg    if (RRCrtcIsLeased(crtc))
17541b5d61b8Smrg        return BadAccess;
17551b5d61b8Smrg
175635c4bbdfSmrg    PictTransform_from_xRenderTransform(&transform, &stuff->transform);
175735c4bbdfSmrg    pixman_f_transform_from_pixman_transform(&f_transform, &transform);
175835c4bbdfSmrg    if (!pixman_f_transform_invert(&f_inverse, &f_transform))
175935c4bbdfSmrg        return BadMatch;
17604642e01fSmrg
17614642e01fSmrg    filter = (char *) (stuff + 1);
17624642e01fSmrg    nbytes = stuff->nbytesFilter;
17636747b715Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
17644642e01fSmrg    nparams = ((xFixed *) stuff + client->req_len) - params;
17654642e01fSmrg    if (nparams < 0)
176635c4bbdfSmrg        return BadLength;
17674642e01fSmrg
176835c4bbdfSmrg    return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
176935c4bbdfSmrg                              filter, nbytes, params, nparams);
17704642e01fSmrg}
17714642e01fSmrg
17724642e01fSmrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
177335c4bbdfSmrg
17744642e01fSmrgstatic int
177535c4bbdfSmrgtransform_filter_length(RRTransformPtr transform)
17764642e01fSmrg{
177735c4bbdfSmrg    int nbytes, nparams;
17784642e01fSmrg
17794642e01fSmrg    if (transform->filter == NULL)
178035c4bbdfSmrg        return 0;
178135c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17824642e01fSmrg    nparams = transform->nparams;
178335c4bbdfSmrg    return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
17844642e01fSmrg}
17854642e01fSmrg
17864642e01fSmrgstatic int
178735c4bbdfSmrgtransform_filter_encode(ClientPtr client, char *output,
178835c4bbdfSmrg                        CARD16 *nbytesFilter,
178935c4bbdfSmrg                        CARD16 *nparamsFilter, RRTransformPtr transform)
17904642e01fSmrg{
179135c4bbdfSmrg    int nbytes, nparams;
17924642e01fSmrg
17934642e01fSmrg    if (transform->filter == NULL) {
179435c4bbdfSmrg        *nbytesFilter = 0;
179535c4bbdfSmrg        *nparamsFilter = 0;
179635c4bbdfSmrg        return 0;
17974642e01fSmrg    }
179835c4bbdfSmrg    nbytes = strlen(transform->filter->name);
17994642e01fSmrg    nparams = transform->nparams;
18004642e01fSmrg    *nbytesFilter = nbytes;
18014642e01fSmrg    *nparamsFilter = nparams;
180235c4bbdfSmrg    memcpy(output, transform->filter->name, nbytes);
18034642e01fSmrg    while ((nbytes & 3) != 0)
180435c4bbdfSmrg        output[nbytes++] = 0;
180535c4bbdfSmrg    memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
18064642e01fSmrg    if (client->swapped) {
180735c4bbdfSmrg        swaps(nbytesFilter);
180835c4bbdfSmrg        swaps(nparamsFilter);
180935c4bbdfSmrg        SwapLongs((CARD32 *) (output + nbytes), nparams);
18104642e01fSmrg    }
181135c4bbdfSmrg    nbytes += nparams * sizeof(xFixed);
18124642e01fSmrg    return nbytes;
18134642e01fSmrg}
18144642e01fSmrg
18154642e01fSmrgstatic void
181635c4bbdfSmrgtransform_encode(ClientPtr client, xRenderTransform * wire,
181735c4bbdfSmrg                 PictTransform * pict)
18184642e01fSmrg{
181935c4bbdfSmrg    xRenderTransform_from_PictTransform(wire, pict);
18204642e01fSmrg    if (client->swapped)
182135c4bbdfSmrg        SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
18224642e01fSmrg}
18234642e01fSmrg
18244642e01fSmrgint
182535c4bbdfSmrgProcRRGetCrtcTransform(ClientPtr client)
18264642e01fSmrg{
18274642e01fSmrg    REQUEST(xRRGetCrtcTransformReq);
182835c4bbdfSmrg    xRRGetCrtcTransformReply *reply;
182935c4bbdfSmrg    RRCrtcPtr crtc;
183035c4bbdfSmrg    int nextra;
183135c4bbdfSmrg    RRTransformPtr current, pending;
183235c4bbdfSmrg    char *extra;
18334642e01fSmrg
183435c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
18356747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
18364642e01fSmrg
18374642e01fSmrg    pending = &crtc->client_pending_transform;
18384642e01fSmrg    current = &crtc->client_current_transform;
18394642e01fSmrg
184035c4bbdfSmrg    nextra = (transform_filter_length(pending) +
184135c4bbdfSmrg              transform_filter_length(current));
18424642e01fSmrg
184335c4bbdfSmrg    reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
18444642e01fSmrg    if (!reply)
184535c4bbdfSmrg        return BadAlloc;
18464642e01fSmrg
18474642e01fSmrg    extra = (char *) (reply + 1);
18484642e01fSmrg    reply->type = X_Reply;
18494642e01fSmrg    reply->sequenceNumber = client->sequence;
18506747b715Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
18514642e01fSmrg
18524642e01fSmrg    reply->hasTransforms = crtc->transforms;
18534642e01fSmrg
185435c4bbdfSmrg    transform_encode(client, &reply->pendingTransform, &pending->transform);
185535c4bbdfSmrg    extra += transform_filter_encode(client, extra,
185635c4bbdfSmrg                                     &reply->pendingNbytesFilter,
185735c4bbdfSmrg                                     &reply->pendingNparamsFilter, pending);
18584642e01fSmrg
185935c4bbdfSmrg    transform_encode(client, &reply->currentTransform, &current->transform);
186035c4bbdfSmrg    extra += transform_filter_encode(client, extra,
186135c4bbdfSmrg                                     &reply->currentNbytesFilter,
186235c4bbdfSmrg                                     &reply->currentNparamsFilter, current);
18634642e01fSmrg
18644642e01fSmrg    if (client->swapped) {
186535c4bbdfSmrg        swaps(&reply->sequenceNumber);
186635c4bbdfSmrg        swapl(&reply->length);
18674642e01fSmrg    }
186835c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
18696747b715Smrg    free(reply);
18706747b715Smrg    return Success;
18714642e01fSmrg}
187235c4bbdfSmrg
187335c4bbdfSmrgstatic Bool
187435c4bbdfSmrgcheck_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
187535c4bbdfSmrg{
187635c4bbdfSmrg    rrScrPriv(pScreen);
187735c4bbdfSmrg    int i;
187835c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
187935c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
188035c4bbdfSmrg
188135c4bbdfSmrg        int left, right, top, bottom;
188235c4bbdfSmrg
18831b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
18841b5d61b8Smrg	    continue;
188535c4bbdfSmrg
188635c4bbdfSmrg        if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
188735c4bbdfSmrg            return TRUE;
188835c4bbdfSmrg    }
188935c4bbdfSmrg    return FALSE;
189035c4bbdfSmrg}
189135c4bbdfSmrg
189235c4bbdfSmrgstatic Bool
189335c4bbdfSmrgconstrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
189435c4bbdfSmrg{
189535c4bbdfSmrg    rrScrPriv(pScreen);
189635c4bbdfSmrg    int i;
189735c4bbdfSmrg
189835c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
189935c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
190035c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
190135c4bbdfSmrg        int nx, ny;
190235c4bbdfSmrg        int left, right, top, bottom;
190335c4bbdfSmrg
19041b5d61b8Smrg        if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
19051b5d61b8Smrg	    continue;
190635c4bbdfSmrg
190735c4bbdfSmrg        miPointerGetPosition(pDev, &nx, &ny);
190835c4bbdfSmrg
190935c4bbdfSmrg        if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
191035c4bbdfSmrg            if (*x < left)
191135c4bbdfSmrg                *x = left;
191235c4bbdfSmrg            if (*x >= right)
191335c4bbdfSmrg                *x = right - 1;
191435c4bbdfSmrg            if (*y < top)
191535c4bbdfSmrg                *y = top;
191635c4bbdfSmrg            if (*y >= bottom)
191735c4bbdfSmrg                *y = bottom - 1;
191835c4bbdfSmrg
191935c4bbdfSmrg            return TRUE;
192035c4bbdfSmrg        }
192135c4bbdfSmrg    }
192235c4bbdfSmrg    return FALSE;
192335c4bbdfSmrg}
192435c4bbdfSmrg
192535c4bbdfSmrgvoid
192635c4bbdfSmrgRRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
192735c4bbdfSmrg                        int *y)
192835c4bbdfSmrg{
192935c4bbdfSmrg    rrScrPriv(pScreen);
193035c4bbdfSmrg    Bool ret;
1931ed6184dfSmrg    ScreenPtr secondary;
193235c4bbdfSmrg
193335c4bbdfSmrg    /* intentional dead space -> let it float */
193435c4bbdfSmrg    if (pScrPriv->discontiguous)
193535c4bbdfSmrg        return;
193635c4bbdfSmrg
193735c4bbdfSmrg    /* if we're moving inside a crtc, we're fine */
193835c4bbdfSmrg    ret = check_all_screen_crtcs(pScreen, x, y);
193935c4bbdfSmrg    if (ret == TRUE)
194035c4bbdfSmrg        return;
194135c4bbdfSmrg
1942ed6184dfSmrg    xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
1943ed6184dfSmrg        if (!secondary->is_output_secondary)
19441b5d61b8Smrg            continue;
19451b5d61b8Smrg
1946ed6184dfSmrg        ret = check_all_screen_crtcs(secondary, x, y);
194735c4bbdfSmrg        if (ret == TRUE)
194835c4bbdfSmrg            return;
194935c4bbdfSmrg    }
195035c4bbdfSmrg
195135c4bbdfSmrg    /* if we're trying to escape, clamp to the CRTC we're coming from */
195235c4bbdfSmrg    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
195335c4bbdfSmrg    if (ret == TRUE)
195435c4bbdfSmrg        return;
195535c4bbdfSmrg
1956ed6184dfSmrg    xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
1957ed6184dfSmrg        if (!secondary->is_output_secondary)
19581b5d61b8Smrg            continue;
19591b5d61b8Smrg
1960ed6184dfSmrg        ret = constrain_all_screen_crtcs(pDev, secondary, x, y);
196135c4bbdfSmrg        if (ret == TRUE)
196235c4bbdfSmrg            return;
196335c4bbdfSmrg    }
196435c4bbdfSmrg}
196535c4bbdfSmrg
196635c4bbdfSmrgBool
196735c4bbdfSmrgRRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
196835c4bbdfSmrg{
196935c4bbdfSmrg    rrScrPriv(pDrawable->pScreen);
197035c4bbdfSmrg    Bool ret = TRUE;
197135c4bbdfSmrg    PixmapPtr *saved_scanout_pixmap;
197235c4bbdfSmrg    int i;
197335c4bbdfSmrg
197435c4bbdfSmrg    saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
197535c4bbdfSmrg    if (saved_scanout_pixmap == NULL)
197635c4bbdfSmrg        return FALSE;
197735c4bbdfSmrg
197835c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
197935c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
198035c4bbdfSmrg        Bool size_fits;
198135c4bbdfSmrg
198235c4bbdfSmrg        saved_scanout_pixmap[i] = crtc->scanout_pixmap;
198335c4bbdfSmrg
198435c4bbdfSmrg        if (!crtc->mode && enable)
198535c4bbdfSmrg            continue;
198635c4bbdfSmrg        if (!crtc->scanout_pixmap && !enable)
198735c4bbdfSmrg            continue;
198835c4bbdfSmrg
19891b5d61b8Smrg        /* not supported with double buffering, needs ABI change for 2 ppix */
19901b5d61b8Smrg        if (crtc->scanout_pixmap_back) {
19911b5d61b8Smrg            ret = FALSE;
19921b5d61b8Smrg            continue;
19931b5d61b8Smrg        }
19941b5d61b8Smrg
199535c4bbdfSmrg        size_fits = (crtc->mode &&
199635c4bbdfSmrg                     crtc->x == pDrawable->x &&
199735c4bbdfSmrg                     crtc->y == pDrawable->y &&
199835c4bbdfSmrg                     crtc->mode->mode.width == pDrawable->width &&
199935c4bbdfSmrg                     crtc->mode->mode.height == pDrawable->height);
200035c4bbdfSmrg
200135c4bbdfSmrg        /* is the pixmap already set? */
200235c4bbdfSmrg        if (crtc->scanout_pixmap == pPixmap) {
200335c4bbdfSmrg            /* if its a disable then don't care about size */
200435c4bbdfSmrg            if (enable == FALSE) {
200535c4bbdfSmrg                /* set scanout to NULL */
200635c4bbdfSmrg                crtc->scanout_pixmap = NULL;
200735c4bbdfSmrg            }
200835c4bbdfSmrg            else if (!size_fits) {
200935c4bbdfSmrg                /* if the size no longer fits then drop off */
201035c4bbdfSmrg                crtc->scanout_pixmap = NULL;
201135c4bbdfSmrg                pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
201235c4bbdfSmrg
201335c4bbdfSmrg                (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
201435c4bbdfSmrg                                        crtc->rotation, crtc->numOutputs, crtc->outputs);
201535c4bbdfSmrg                saved_scanout_pixmap[i] = crtc->scanout_pixmap;
201635c4bbdfSmrg                ret = FALSE;
201735c4bbdfSmrg            }
201835c4bbdfSmrg            else {
201935c4bbdfSmrg                /* if the size fits then we are already setup */
202035c4bbdfSmrg            }
202135c4bbdfSmrg        }
202235c4bbdfSmrg        else {
202335c4bbdfSmrg            if (!size_fits)
202435c4bbdfSmrg                ret = FALSE;
202535c4bbdfSmrg            else if (enable)
202635c4bbdfSmrg                crtc->scanout_pixmap = pPixmap;
202735c4bbdfSmrg            else
202835c4bbdfSmrg                /* reject an attempt to disable someone else's scanout_pixmap */
202935c4bbdfSmrg                ret = FALSE;
203035c4bbdfSmrg        }
203135c4bbdfSmrg    }
203235c4bbdfSmrg
203335c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
203435c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
203535c4bbdfSmrg
203635c4bbdfSmrg        if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
203735c4bbdfSmrg            continue;
203835c4bbdfSmrg
203935c4bbdfSmrg        if (ret) {
204035c4bbdfSmrg            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
204135c4bbdfSmrg
204235c4bbdfSmrg            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
204335c4bbdfSmrg                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
204435c4bbdfSmrg        }
204535c4bbdfSmrg        else
204635c4bbdfSmrg            crtc->scanout_pixmap = saved_scanout_pixmap[i];
204735c4bbdfSmrg    }
204835c4bbdfSmrg    free(saved_scanout_pixmap);
204935c4bbdfSmrg
205035c4bbdfSmrg    return ret;
205135c4bbdfSmrg}
20521b5d61b8Smrg
20531b5d61b8SmrgBool
20541b5d61b8SmrgRRHasScanoutPixmap(ScreenPtr pScreen)
20551b5d61b8Smrg{
20565a7dfde8Smrg    rrScrPrivPtr pScrPriv;
20571b5d61b8Smrg    int i;
20581b5d61b8Smrg
20595a7dfde8Smrg    /* Bail out if RandR wasn't initialized. */
20605a7dfde8Smrg    if (!dixPrivateKeyRegistered(rrPrivKey))
20615a7dfde8Smrg        return FALSE;
20625a7dfde8Smrg
20635a7dfde8Smrg    pScrPriv = rrGetScrPriv(pScreen);
20645a7dfde8Smrg
2065ed6184dfSmrg    if (!pScreen->is_output_secondary)
20661b5d61b8Smrg        return FALSE;
20671b5d61b8Smrg
20681b5d61b8Smrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
20691b5d61b8Smrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
20701b5d61b8Smrg
20711b5d61b8Smrg        if (crtc->scanout_pixmap)
20721b5d61b8Smrg            return TRUE;
20731b5d61b8Smrg    }
20741b5d61b8Smrg
20751b5d61b8Smrg    return FALSE;
20761b5d61b8Smrg}
2077