rrcrtc.c revision 6747b715
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2006 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
605b261ecSmrg * the above copyright notice appear in all copies and that both that copyright
705b261ecSmrg * notice and this permission notice appear in supporting documentation, and
805b261ecSmrg * that the name of the copyright holders not be used in advertising or
905b261ecSmrg * publicity pertaining to distribution of the software without specific,
1005b261ecSmrg * written prior permission.  The copyright holders make no representations
1105b261ecSmrg * about the suitability of this software for any purpose.  It is provided "as
1205b261ecSmrg * is" without express or implied warranty.
1305b261ecSmrg *
1405b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1605b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2005b261ecSmrg * OF THIS SOFTWARE.
2105b261ecSmrg */
2205b261ecSmrg
2305b261ecSmrg#include "randrstr.h"
2405b261ecSmrg#include "swaprep.h"
2505b261ecSmrg
2605b261ecSmrgRESTYPE	RRCrtcType;
2705b261ecSmrg
2805b261ecSmrg/*
2905b261ecSmrg * Notify the CRTC of some change
3005b261ecSmrg */
3105b261ecSmrgvoid
3205b261ecSmrgRRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
3305b261ecSmrg{
3405b261ecSmrg    ScreenPtr	pScreen = crtc->pScreen;
3505b261ecSmrg
3605b261ecSmrg    crtc->changed = TRUE;
3705b261ecSmrg    if (pScreen)
3805b261ecSmrg    {
3905b261ecSmrg	rrScrPriv(pScreen);
4005b261ecSmrg
4105b261ecSmrg	pScrPriv->changed = TRUE;
4205b261ecSmrg	/*
4305b261ecSmrg	 * Send ConfigureNotify on any layout change
4405b261ecSmrg	 */
4505b261ecSmrg	if (layoutChanged)
4605b261ecSmrg	    pScrPriv->layoutChanged = TRUE;
4705b261ecSmrg    }
4805b261ecSmrg}
4905b261ecSmrg
5005b261ecSmrg/*
5105b261ecSmrg * Create a CRTC
5205b261ecSmrg */
5305b261ecSmrgRRCrtcPtr
5405b261ecSmrgRRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
5505b261ecSmrg{
5605b261ecSmrg    RRCrtcPtr	    crtc;
5705b261ecSmrg    RRCrtcPtr	    *crtcs;
5805b261ecSmrg    rrScrPrivPtr    pScrPriv;
5905b261ecSmrg
6005b261ecSmrg    if (!RRInit())
6105b261ecSmrg	return NULL;
6205b261ecSmrg
6305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
6405b261ecSmrg
6505b261ecSmrg    /* make space for the crtc pointer */
6605b261ecSmrg    if (pScrPriv->numCrtcs)
676747b715Smrg	crtcs = realloc(pScrPriv->crtcs,
6805b261ecSmrg			  (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
6905b261ecSmrg    else
706747b715Smrg	crtcs = malloc(sizeof (RRCrtcPtr));
7105b261ecSmrg    if (!crtcs)
7205b261ecSmrg	return FALSE;
7305b261ecSmrg    pScrPriv->crtcs = crtcs;
7405b261ecSmrg
756747b715Smrg    crtc = calloc(1, sizeof (RRCrtcRec));
7605b261ecSmrg    if (!crtc)
7705b261ecSmrg	return NULL;
7805b261ecSmrg    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;
914642e01fSmrg    RRTransformInit (&crtc->client_pending_transform);
924642e01fSmrg    RRTransformInit (&crtc->client_current_transform);
934642e01fSmrg    pixman_transform_init_identity (&crtc->transform);
944642e01fSmrg    pixman_f_transform_init_identity (&crtc->f_transform);
954642e01fSmrg    pixman_f_transform_init_identity (&crtc->f_inverse);
9605b261ecSmrg
9705b261ecSmrg    if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
9805b261ecSmrg	return NULL;
9905b261ecSmrg
10005b261ecSmrg    /* attach the screen and crtc together */
10105b261ecSmrg    crtc->pScreen = pScreen;
10205b261ecSmrg    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
10305b261ecSmrg
10405b261ecSmrg    return crtc;
10505b261ecSmrg}
10605b261ecSmrg
10705b261ecSmrg/*
10805b261ecSmrg * Set the allowed rotations on a CRTC
10905b261ecSmrg */
11005b261ecSmrgvoid
11105b261ecSmrgRRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
11205b261ecSmrg{
11305b261ecSmrg    crtc->rotations = rotations;
11405b261ecSmrg}
11505b261ecSmrg
1164642e01fSmrg/*
1174642e01fSmrg * Set whether transforms are allowed on a CRTC
1184642e01fSmrg */
1194642e01fSmrgvoid
1204642e01fSmrgRRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
1214642e01fSmrg{
1224642e01fSmrg    crtc->transforms = transforms;
1234642e01fSmrg}
1244642e01fSmrg
12505b261ecSmrg/*
12605b261ecSmrg * Notify the extension that the Crtc has been reconfigured,
12705b261ecSmrg * the driver calls this whenever it has updated the mode
12805b261ecSmrg */
12905b261ecSmrgBool
13005b261ecSmrgRRCrtcNotify (RRCrtcPtr	    crtc,
13105b261ecSmrg	      RRModePtr	    mode,
13205b261ecSmrg	      int	    x,
13305b261ecSmrg	      int	    y,
13405b261ecSmrg	      Rotation	    rotation,
1354642e01fSmrg	      RRTransformPtr transform,
13605b261ecSmrg	      int	    numOutputs,
13705b261ecSmrg	      RROutputPtr   *outputs)
13805b261ecSmrg{
13905b261ecSmrg    int	    i, j;
14005b261ecSmrg
14105b261ecSmrg    /*
14205b261ecSmrg     * Check to see if any of the new outputs were
14305b261ecSmrg     * not in the old list and mark them as changed
14405b261ecSmrg     */
14505b261ecSmrg    for (i = 0; i < numOutputs; i++)
14605b261ecSmrg    {
14705b261ecSmrg	for (j = 0; j < crtc->numOutputs; j++)
14805b261ecSmrg	    if (outputs[i] == crtc->outputs[j])
14905b261ecSmrg		break;
15005b261ecSmrg	if (j == crtc->numOutputs)
15105b261ecSmrg	{
15205b261ecSmrg	    outputs[i]->crtc = crtc;
15305b261ecSmrg	    RROutputChanged (outputs[i], FALSE);
15405b261ecSmrg	    RRCrtcChanged (crtc, FALSE);
15505b261ecSmrg	}
15605b261ecSmrg    }
15705b261ecSmrg    /*
15805b261ecSmrg     * Check to see if any of the old outputs are
15905b261ecSmrg     * not in the new list and mark them as changed
16005b261ecSmrg     */
16105b261ecSmrg    for (j = 0; j < crtc->numOutputs; j++)
16205b261ecSmrg    {
16305b261ecSmrg	for (i = 0; i < numOutputs; i++)
16405b261ecSmrg	    if (outputs[i] == crtc->outputs[j])
16505b261ecSmrg		break;
16605b261ecSmrg	if (i == numOutputs)
16705b261ecSmrg	{
1684642e01fSmrg	    if (crtc->outputs[j]->crtc == crtc)
1694642e01fSmrg		crtc->outputs[j]->crtc = NULL;
17005b261ecSmrg	    RROutputChanged (crtc->outputs[j], FALSE);
17105b261ecSmrg	    RRCrtcChanged (crtc, FALSE);
17205b261ecSmrg	}
17305b261ecSmrg    }
17405b261ecSmrg    /*
17505b261ecSmrg     * Reallocate the crtc output array if necessary
17605b261ecSmrg     */
17705b261ecSmrg    if (numOutputs != crtc->numOutputs)
17805b261ecSmrg    {
17905b261ecSmrg	RROutputPtr *newoutputs;
18005b261ecSmrg
18105b261ecSmrg	if (numOutputs)
18205b261ecSmrg	{
18305b261ecSmrg	    if (crtc->numOutputs)
1846747b715Smrg		newoutputs = realloc(crtc->outputs,
18505b261ecSmrg				    numOutputs * sizeof (RROutputPtr));
18605b261ecSmrg	    else
1876747b715Smrg		newoutputs = malloc(numOutputs * sizeof (RROutputPtr));
18805b261ecSmrg	    if (!newoutputs)
18905b261ecSmrg		return FALSE;
19005b261ecSmrg	}
19105b261ecSmrg	else
19205b261ecSmrg	{
1936747b715Smrg	    free(crtc->outputs);
19405b261ecSmrg	    newoutputs = NULL;
19505b261ecSmrg	}
19605b261ecSmrg	crtc->outputs = newoutputs;
19705b261ecSmrg	crtc->numOutputs = numOutputs;
19805b261ecSmrg    }
19905b261ecSmrg    /*
20005b261ecSmrg     * Copy the new list of outputs into the crtc
20105b261ecSmrg     */
20205b261ecSmrg    memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
20305b261ecSmrg    /*
20405b261ecSmrg     * Update remaining crtc fields
20505b261ecSmrg     */
20605b261ecSmrg    if (mode != crtc->mode)
20705b261ecSmrg    {
20805b261ecSmrg	if (crtc->mode)
20905b261ecSmrg	    RRModeDestroy (crtc->mode);
21005b261ecSmrg	crtc->mode = mode;
21105b261ecSmrg	if (mode != NULL)
21205b261ecSmrg	    mode->refcnt++;
21305b261ecSmrg	RRCrtcChanged (crtc, TRUE);
21405b261ecSmrg    }
21505b261ecSmrg    if (x != crtc->x)
21605b261ecSmrg    {
21705b261ecSmrg	crtc->x = x;
21805b261ecSmrg	RRCrtcChanged (crtc, TRUE);
21905b261ecSmrg    }
22005b261ecSmrg    if (y != crtc->y)
22105b261ecSmrg    {
22205b261ecSmrg	crtc->y = y;
22305b261ecSmrg	RRCrtcChanged (crtc, TRUE);
22405b261ecSmrg    }
22505b261ecSmrg    if (rotation != crtc->rotation)
22605b261ecSmrg    {
22705b261ecSmrg	crtc->rotation = rotation;
22805b261ecSmrg	RRCrtcChanged (crtc, TRUE);
22905b261ecSmrg    }
2304642e01fSmrg    if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
2314642e01fSmrg	RRTransformCopy (&crtc->client_current_transform, transform);
2324642e01fSmrg	RRCrtcChanged (crtc, TRUE);
2334642e01fSmrg    }
2344642e01fSmrg    if (crtc->changed && mode)
2354642e01fSmrg    {
2364642e01fSmrg	RRTransformCompute (x, y,
2374642e01fSmrg			    mode->mode.width, mode->mode.height,
2384642e01fSmrg			    rotation,
2394642e01fSmrg			    &crtc->client_current_transform,
2404642e01fSmrg			    &crtc->transform, &crtc->f_transform,
2414642e01fSmrg			    &crtc->f_inverse);
2424642e01fSmrg    }
24305b261ecSmrg    return TRUE;
24405b261ecSmrg}
24505b261ecSmrg
24605b261ecSmrgvoid
24705b261ecSmrgRRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
24805b261ecSmrg{
24905b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
25005b261ecSmrg    rrScrPriv (pScreen);
25105b261ecSmrg    xRRCrtcChangeNotifyEvent	ce;
25205b261ecSmrg    RRModePtr	mode = crtc->mode;
25305b261ecSmrg
25405b261ecSmrg    ce.type = RRNotify + RREventBase;
25505b261ecSmrg    ce.subCode = RRNotify_CrtcChange;
25605b261ecSmrg    ce.timestamp = pScrPriv->lastSetTime.milliseconds;
25705b261ecSmrg    ce.window = pWin->drawable.id;
25805b261ecSmrg    ce.crtc = crtc->id;
25905b261ecSmrg    ce.rotation = crtc->rotation;
26005b261ecSmrg    if (mode)
26105b261ecSmrg    {
26205b261ecSmrg	ce.mode = mode->mode.id;
26305b261ecSmrg	ce.x = crtc->x;
26405b261ecSmrg	ce.y = crtc->y;
26505b261ecSmrg	ce.width = mode->mode.width;
26605b261ecSmrg	ce.height = mode->mode.height;
26705b261ecSmrg    }
26805b261ecSmrg    else
26905b261ecSmrg    {
27005b261ecSmrg	ce.mode = None;
27105b261ecSmrg	ce.x = 0;
27205b261ecSmrg	ce.y = 0;
27305b261ecSmrg	ce.width = 0;
27405b261ecSmrg	ce.height = 0;
27505b261ecSmrg    }
27605b261ecSmrg    WriteEventsToClient (client, 1, (xEvent *) &ce);
27705b261ecSmrg}
27805b261ecSmrg
27905b261ecSmrgstatic Bool
28005b261ecSmrgRRCrtcPendingProperties (RRCrtcPtr crtc)
28105b261ecSmrg{
28205b261ecSmrg    ScreenPtr	pScreen = crtc->pScreen;
28305b261ecSmrg    rrScrPriv(pScreen);
28405b261ecSmrg    int		o;
28505b261ecSmrg
28605b261ecSmrg    for (o = 0; o < pScrPriv->numOutputs; o++)
28705b261ecSmrg    {
28805b261ecSmrg	RROutputPtr output = pScrPriv->outputs[o];
28905b261ecSmrg	if (output->crtc == crtc && output->pendingProperties)
29005b261ecSmrg	    return TRUE;
29105b261ecSmrg    }
29205b261ecSmrg    return FALSE;
29305b261ecSmrg}
29405b261ecSmrg
29505b261ecSmrg/*
29605b261ecSmrg * Request that the Crtc be reconfigured
29705b261ecSmrg */
29805b261ecSmrgBool
29905b261ecSmrgRRCrtcSet (RRCrtcPtr    crtc,
30005b261ecSmrg	   RRModePtr	mode,
30105b261ecSmrg	   int		x,
30205b261ecSmrg	   int		y,
30305b261ecSmrg	   Rotation	rotation,
30405b261ecSmrg	   int		numOutputs,
30505b261ecSmrg	   RROutputPtr  *outputs)
30605b261ecSmrg{
30705b261ecSmrg    ScreenPtr	pScreen = crtc->pScreen;
30805b261ecSmrg    Bool	ret = FALSE;
30905b261ecSmrg    rrScrPriv(pScreen);
31005b261ecSmrg
31105b261ecSmrg    /* See if nothing changed */
31205b261ecSmrg    if (crtc->mode == mode &&
31305b261ecSmrg	crtc->x == x &&
31405b261ecSmrg	crtc->y == y &&
31505b261ecSmrg	crtc->rotation == rotation &&
31605b261ecSmrg	crtc->numOutputs == numOutputs &&
31705b261ecSmrg	!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
3184642e01fSmrg	!RRCrtcPendingProperties (crtc) &&
3194642e01fSmrg	!RRCrtcPendingTransform (crtc))
32005b261ecSmrg    {
32105b261ecSmrg	ret = TRUE;
32205b261ecSmrg    }
32305b261ecSmrg    else
32405b261ecSmrg    {
32505b261ecSmrg#if RANDR_12_INTERFACE
32605b261ecSmrg	if (pScrPriv->rrCrtcSet)
32705b261ecSmrg	{
32805b261ecSmrg	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
32905b261ecSmrg					  rotation, numOutputs, outputs);
33005b261ecSmrg	}
33105b261ecSmrg	else
33205b261ecSmrg#endif
33305b261ecSmrg	{
33405b261ecSmrg#if RANDR_10_INTERFACE
33505b261ecSmrg	    if (pScrPriv->rrSetConfig)
33605b261ecSmrg	    {
33705b261ecSmrg		RRScreenSize	    size;
33805b261ecSmrg		RRScreenRate	    rate;
33905b261ecSmrg
34005b261ecSmrg		if (!mode)
34105b261ecSmrg		{
3424642e01fSmrg		    RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
34305b261ecSmrg		    ret = TRUE;
34405b261ecSmrg		}
34505b261ecSmrg		else
34605b261ecSmrg		{
34705b261ecSmrg		    size.width = mode->mode.width;
34805b261ecSmrg		    size.height = mode->mode.height;
34905b261ecSmrg		    if (outputs[0]->mmWidth && outputs[0]->mmHeight)
35005b261ecSmrg		    {
35105b261ecSmrg			size.mmWidth = outputs[0]->mmWidth;
35205b261ecSmrg			size.mmHeight = outputs[0]->mmHeight;
35305b261ecSmrg		    }
35405b261ecSmrg		    else
35505b261ecSmrg		    {
35605b261ecSmrg			size.mmWidth = pScreen->mmWidth;
35705b261ecSmrg			size.mmHeight = pScreen->mmHeight;
35805b261ecSmrg		    }
35905b261ecSmrg		    size.nRates = 1;
36005b261ecSmrg		    rate.rate = RRVerticalRefresh (&mode->mode);
36105b261ecSmrg		    size.pRates = &rate;
36205b261ecSmrg		    ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
36305b261ecSmrg		    /*
36405b261ecSmrg		     * Old 1.0 interface tied screen size to mode size
36505b261ecSmrg		     */
36605b261ecSmrg		    if (ret)
36705b261ecSmrg		    {
3684642e01fSmrg			RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
36905b261ecSmrg			RRScreenSizeNotify (pScreen);
37005b261ecSmrg		    }
37105b261ecSmrg		}
37205b261ecSmrg	    }
37305b261ecSmrg#endif
37405b261ecSmrg	}
37505b261ecSmrg	if (ret)
37605b261ecSmrg	{
37705b261ecSmrg	    int	o;
37805b261ecSmrg	    RRTellChanged (pScreen);
37905b261ecSmrg
38005b261ecSmrg	    for (o = 0; o < numOutputs; o++)
38105b261ecSmrg		RRPostPendingProperties (outputs[o]);
38205b261ecSmrg	}
38305b261ecSmrg    }
38405b261ecSmrg    return ret;
38505b261ecSmrg}
38605b261ecSmrg
3874642e01fSmrg/*
3884642e01fSmrg * Return crtc transform
3894642e01fSmrg */
3904642e01fSmrgRRTransformPtr
3914642e01fSmrgRRCrtcGetTransform (RRCrtcPtr crtc)
3924642e01fSmrg{
3934642e01fSmrg    RRTransformPtr  transform = &crtc->client_pending_transform;
3944642e01fSmrg
3954642e01fSmrg    if (pixman_transform_is_identity (&transform->transform))
3964642e01fSmrg	return NULL;
3974642e01fSmrg    return transform;
3984642e01fSmrg}
3994642e01fSmrg
4004642e01fSmrg/*
4014642e01fSmrg * Check whether the pending and current transforms are the same
4024642e01fSmrg */
4034642e01fSmrgBool
4044642e01fSmrgRRCrtcPendingTransform (RRCrtcPtr crtc)
4054642e01fSmrg{
4064642e01fSmrg    return memcmp (&crtc->client_current_transform.transform,
4074642e01fSmrg		   &crtc->client_pending_transform.transform,
4084642e01fSmrg		   sizeof (PictTransform)) != 0;
4094642e01fSmrg}
4104642e01fSmrg
41105b261ecSmrg/*
41205b261ecSmrg * Destroy a Crtc at shutdown
41305b261ecSmrg */
41405b261ecSmrgvoid
41505b261ecSmrgRRCrtcDestroy (RRCrtcPtr crtc)
41605b261ecSmrg{
41705b261ecSmrg    FreeResource (crtc->id, 0);
41805b261ecSmrg}
41905b261ecSmrg
42005b261ecSmrgstatic int
42105b261ecSmrgRRCrtcDestroyResource (pointer value, XID pid)
42205b261ecSmrg{
42305b261ecSmrg    RRCrtcPtr	crtc = (RRCrtcPtr) value;
42405b261ecSmrg    ScreenPtr	pScreen = crtc->pScreen;
42505b261ecSmrg
42605b261ecSmrg    if (pScreen)
42705b261ecSmrg    {
42805b261ecSmrg	rrScrPriv(pScreen);
42905b261ecSmrg	int		i;
43005b261ecSmrg
43105b261ecSmrg	for (i = 0; i < pScrPriv->numCrtcs; i++)
43205b261ecSmrg	{
43305b261ecSmrg	    if (pScrPriv->crtcs[i] == crtc)
43405b261ecSmrg	    {
43505b261ecSmrg		memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
43605b261ecSmrg			 (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
43705b261ecSmrg		--pScrPriv->numCrtcs;
43805b261ecSmrg		break;
43905b261ecSmrg	    }
44005b261ecSmrg	}
44105b261ecSmrg    }
4426747b715Smrg    free(crtc->gammaRed);
44305b261ecSmrg    if (crtc->mode)
44405b261ecSmrg	RRModeDestroy (crtc->mode);
4456747b715Smrg    free(crtc);
44605b261ecSmrg    return 1;
44705b261ecSmrg}
44805b261ecSmrg
44905b261ecSmrg/*
45005b261ecSmrg * Request that the Crtc gamma be changed
45105b261ecSmrg */
45205b261ecSmrg
45305b261ecSmrgBool
45405b261ecSmrgRRCrtcGammaSet (RRCrtcPtr   crtc,
45505b261ecSmrg		CARD16	    *red,
45605b261ecSmrg		CARD16	    *green,
45705b261ecSmrg		CARD16	    *blue)
45805b261ecSmrg{
45905b261ecSmrg    Bool	ret = TRUE;
46005b261ecSmrg#if RANDR_12_INTERFACE
46105b261ecSmrg    ScreenPtr	pScreen = crtc->pScreen;
46205b261ecSmrg#endif
46305b261ecSmrg
46405b261ecSmrg    memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
46505b261ecSmrg    memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
46605b261ecSmrg    memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
46705b261ecSmrg#if RANDR_12_INTERFACE
46805b261ecSmrg    if (pScreen)
46905b261ecSmrg    {
47005b261ecSmrg	rrScrPriv(pScreen);
47105b261ecSmrg	if (pScrPriv->rrCrtcSetGamma)
47205b261ecSmrg	    ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
47305b261ecSmrg    }
47405b261ecSmrg#endif
47505b261ecSmrg    return ret;
47605b261ecSmrg}
47705b261ecSmrg
4786747b715Smrg/*
4796747b715Smrg * Request current gamma back from the DDX (if possible).
4806747b715Smrg * This includes gamma size.
4816747b715Smrg */
4826747b715SmrgBool
4836747b715SmrgRRCrtcGammaGet(RRCrtcPtr crtc)
4846747b715Smrg{
4856747b715Smrg    Bool ret = TRUE;
4866747b715Smrg#if RANDR_12_INTERFACE
4876747b715Smrg    ScreenPtr	pScreen = crtc->pScreen;
4886747b715Smrg#endif
4896747b715Smrg
4906747b715Smrg#if RANDR_12_INTERFACE
4916747b715Smrg    if (pScreen)
4926747b715Smrg    {
4936747b715Smrg        rrScrPriv(pScreen);
4946747b715Smrg        if (pScrPriv->rrCrtcGetGamma)
4956747b715Smrg            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
4966747b715Smrg    }
4976747b715Smrg#endif
4986747b715Smrg    return ret;
4996747b715Smrg}
5006747b715Smrg
50105b261ecSmrg/*
50205b261ecSmrg * Notify the extension that the Crtc gamma has been changed
50305b261ecSmrg * The driver calls this whenever it has changed the gamma values
50405b261ecSmrg * in the RRCrtcRec
50505b261ecSmrg */
50605b261ecSmrg
50705b261ecSmrgBool
50805b261ecSmrgRRCrtcGammaNotify (RRCrtcPtr	crtc)
50905b261ecSmrg{
51005b261ecSmrg    return TRUE;    /* not much going on here */
51105b261ecSmrg}
51205b261ecSmrg
5134642e01fSmrgstatic void
5144642e01fSmrgRRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
5154642e01fSmrg		      int *width, int *height)
51605b261ecSmrg{
5174642e01fSmrg    BoxRec  box;
5184642e01fSmrg
5194642e01fSmrg    if (mode == NULL) {
52005b261ecSmrg	*width = 0;
52105b261ecSmrg	*height = 0;
52205b261ecSmrg	return;
52305b261ecSmrg    }
52405b261ecSmrg
5254642e01fSmrg    box.x1 = 0;
5264642e01fSmrg    box.y1 = 0;
5274642e01fSmrg    box.x2 = mode->mode.width;
5284642e01fSmrg    box.y2 = mode->mode.height;
5294642e01fSmrg
5304642e01fSmrg    pixman_transform_bounds (transform, &box);
5314642e01fSmrg    *width = box.x2 - box.x1;
5324642e01fSmrg    *height = box.y2 - box.y1;
5334642e01fSmrg}
5344642e01fSmrg
5354642e01fSmrg/**
5364642e01fSmrg * Returns the width/height that the crtc scans out from the framebuffer
5374642e01fSmrg */
5384642e01fSmrgvoid
5394642e01fSmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
5404642e01fSmrg{
5414642e01fSmrg    return RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
54205b261ecSmrg}
54305b261ecSmrg
54405b261ecSmrg/*
54505b261ecSmrg * Set the size of the gamma table at server startup time
54605b261ecSmrg */
54705b261ecSmrg
54805b261ecSmrgBool
54905b261ecSmrgRRCrtcGammaSetSize (RRCrtcPtr	crtc,
55005b261ecSmrg		    int		size)
55105b261ecSmrg{
55205b261ecSmrg    CARD16  *gamma;
55305b261ecSmrg
55405b261ecSmrg    if (size == crtc->gammaSize)
55505b261ecSmrg	return TRUE;
55605b261ecSmrg    if (size)
55705b261ecSmrg    {
5586747b715Smrg	gamma = malloc(size * 3 * sizeof (CARD16));
55905b261ecSmrg	if (!gamma)
56005b261ecSmrg	    return FALSE;
56105b261ecSmrg    }
56205b261ecSmrg    else
56305b261ecSmrg	gamma = NULL;
5646747b715Smrg    free(crtc->gammaRed);
56505b261ecSmrg    crtc->gammaRed = gamma;
56605b261ecSmrg    crtc->gammaGreen = gamma + size;
56705b261ecSmrg    crtc->gammaBlue = gamma + size*2;
56805b261ecSmrg    crtc->gammaSize = size;
56905b261ecSmrg    return TRUE;
57005b261ecSmrg}
57105b261ecSmrg
5724642e01fSmrg/*
5734642e01fSmrg * Set the pending CRTC transformation
5744642e01fSmrg */
5754642e01fSmrg
5764642e01fSmrgint
5774642e01fSmrgRRCrtcTransformSet (RRCrtcPtr		crtc,
5784642e01fSmrg		    PictTransformPtr	transform,
5794642e01fSmrg		    struct pixman_f_transform *f_transform,
5804642e01fSmrg		    struct pixman_f_transform *f_inverse,
5814642e01fSmrg		    char		*filter_name,
5824642e01fSmrg		    int			filter_len,
5834642e01fSmrg		    xFixed		*params,
5844642e01fSmrg		    int			nparams)
5854642e01fSmrg{
5864642e01fSmrg    PictFilterPtr   filter = NULL;
5874642e01fSmrg    int		    width = 0, height = 0;
5884642e01fSmrg
5894642e01fSmrg    if (!crtc->transforms)
5904642e01fSmrg	return BadValue;
5914642e01fSmrg
5924642e01fSmrg    if (filter_len)
5934642e01fSmrg    {
5944642e01fSmrg	filter = PictureFindFilter (crtc->pScreen,
5954642e01fSmrg				    filter_name,
5964642e01fSmrg				    filter_len);
5974642e01fSmrg	if (!filter)
5984642e01fSmrg	    return BadName;
5994642e01fSmrg	if (filter->ValidateParams)
6004642e01fSmrg	{
6014642e01fSmrg	    if (!filter->ValidateParams (crtc->pScreen, filter->id,
6024642e01fSmrg					 params, nparams, &width, &height))
6034642e01fSmrg		return BadMatch;
6044642e01fSmrg	}
6054642e01fSmrg	else {
6064642e01fSmrg	    width = filter->width;
6074642e01fSmrg	    height = filter->height;
6084642e01fSmrg	}
6094642e01fSmrg    }
6104642e01fSmrg    else
6114642e01fSmrg    {
6124642e01fSmrg	if (nparams)
6134642e01fSmrg	    return BadMatch;
6144642e01fSmrg    }
6154642e01fSmrg    if (!RRTransformSetFilter (&crtc->client_pending_transform,
6164642e01fSmrg			       filter, params, nparams, width, height))
6174642e01fSmrg	return BadAlloc;
6184642e01fSmrg
6194642e01fSmrg    crtc->client_pending_transform.transform = *transform;
6204642e01fSmrg    crtc->client_pending_transform.f_transform = *f_transform;
6214642e01fSmrg    crtc->client_pending_transform.f_inverse = *f_inverse;
6224642e01fSmrg    return Success;
6234642e01fSmrg}
6244642e01fSmrg
62505b261ecSmrg/*
62605b261ecSmrg * Initialize crtc type
62705b261ecSmrg */
62805b261ecSmrgBool
62905b261ecSmrgRRCrtcInit (void)
63005b261ecSmrg{
6316747b715Smrg    RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
63205b261ecSmrg    if (!RRCrtcType)
63305b261ecSmrg	return FALSE;
6346747b715Smrg
63505b261ecSmrg    return TRUE;
63605b261ecSmrg}
63705b261ecSmrg
6386747b715Smrg/*
6396747b715Smrg * Initialize crtc type error value
6406747b715Smrg */
6416747b715Smrgvoid
6426747b715SmrgRRCrtcInitErrorValue(void)
6436747b715Smrg{
6446747b715Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
6456747b715Smrg}
6466747b715Smrg
64705b261ecSmrgint
64805b261ecSmrgProcRRGetCrtcInfo (ClientPtr client)
64905b261ecSmrg{
65005b261ecSmrg    REQUEST(xRRGetCrtcInfoReq);
65105b261ecSmrg    xRRGetCrtcInfoReply	rep;
65205b261ecSmrg    RRCrtcPtr			crtc;
65305b261ecSmrg    CARD8			*extra;
65405b261ecSmrg    unsigned long		extraLen;
65505b261ecSmrg    ScreenPtr			pScreen;
65605b261ecSmrg    rrScrPrivPtr		pScrPriv;
65705b261ecSmrg    RRModePtr			mode;
65805b261ecSmrg    RROutput			*outputs;
65905b261ecSmrg    RROutput			*possible;
66005b261ecSmrg    int				i, j, k, n;
66105b261ecSmrg    int				width, height;
6624642e01fSmrg    BoxRec			panned_area;
66305b261ecSmrg
66405b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
6656747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
66605b261ecSmrg
66705b261ecSmrg    /* All crtcs must be associated with screens before client
66805b261ecSmrg     * requests are processed
66905b261ecSmrg     */
67005b261ecSmrg    pScreen = crtc->pScreen;
67105b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
67205b261ecSmrg
67305b261ecSmrg    mode = crtc->mode;
67405b261ecSmrg
67505b261ecSmrg    rep.type = X_Reply;
67605b261ecSmrg    rep.status = RRSetConfigSuccess;
67705b261ecSmrg    rep.sequenceNumber = client->sequence;
67805b261ecSmrg    rep.length = 0;
67905b261ecSmrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
6804642e01fSmrg    if (pScrPriv->rrGetPanning &&
6814642e01fSmrg	pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
6824642e01fSmrg	(panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
6834642e01fSmrg    {
6844642e01fSmrg 	rep.x = panned_area.x1;
6854642e01fSmrg	rep.y = panned_area.y1;
6864642e01fSmrg	rep.width = panned_area.x2 - panned_area.x1;
6874642e01fSmrg	rep.height = panned_area.y2 - panned_area.y1;
6884642e01fSmrg    }
6894642e01fSmrg    else
6904642e01fSmrg    {
6914642e01fSmrg	RRCrtcGetScanoutSize (crtc, &width, &height);
6924642e01fSmrg	rep.x = crtc->x;
6934642e01fSmrg	rep.y = crtc->y;
6944642e01fSmrg	rep.width = width;
6954642e01fSmrg	rep.height = height;
6964642e01fSmrg    }
69705b261ecSmrg    rep.mode = mode ? mode->mode.id : 0;
69805b261ecSmrg    rep.rotation = crtc->rotation;
69905b261ecSmrg    rep.rotations = crtc->rotations;
70005b261ecSmrg    rep.nOutput = crtc->numOutputs;
70105b261ecSmrg    k = 0;
70205b261ecSmrg    for (i = 0; i < pScrPriv->numOutputs; i++)
70305b261ecSmrg	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
70405b261ecSmrg	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
70505b261ecSmrg		k++;
70605b261ecSmrg    rep.nPossibleOutput = k;
70705b261ecSmrg
70805b261ecSmrg    rep.length = rep.nOutput + rep.nPossibleOutput;
70905b261ecSmrg
71005b261ecSmrg    extraLen = rep.length << 2;
71105b261ecSmrg    if (extraLen)
71205b261ecSmrg    {
7136747b715Smrg	extra = malloc(extraLen);
71405b261ecSmrg	if (!extra)
71505b261ecSmrg	    return BadAlloc;
71605b261ecSmrg    }
71705b261ecSmrg    else
71805b261ecSmrg	extra = NULL;
71905b261ecSmrg
72005b261ecSmrg    outputs = (RROutput *) extra;
72105b261ecSmrg    possible = (RROutput *) (outputs + rep.nOutput);
72205b261ecSmrg
72305b261ecSmrg    for (i = 0; i < crtc->numOutputs; i++)
72405b261ecSmrg    {
72505b261ecSmrg	outputs[i] = crtc->outputs[i]->id;
72605b261ecSmrg	if (client->swapped)
72705b261ecSmrg	    swapl (&outputs[i], n);
72805b261ecSmrg    }
72905b261ecSmrg    k = 0;
73005b261ecSmrg    for (i = 0; i < pScrPriv->numOutputs; i++)
73105b261ecSmrg	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
73205b261ecSmrg	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
73305b261ecSmrg	    {
73405b261ecSmrg		possible[k] = pScrPriv->outputs[i]->id;
73505b261ecSmrg		if (client->swapped)
73605b261ecSmrg		    swapl (&possible[k], n);
73705b261ecSmrg		k++;
73805b261ecSmrg	    }
73905b261ecSmrg
74005b261ecSmrg    if (client->swapped) {
74105b261ecSmrg	swaps(&rep.sequenceNumber, n);
74205b261ecSmrg	swapl(&rep.length, n);
74305b261ecSmrg	swapl(&rep.timestamp, n);
74405b261ecSmrg	swaps(&rep.x, n);
74505b261ecSmrg	swaps(&rep.y, n);
74605b261ecSmrg	swaps(&rep.width, n);
74705b261ecSmrg	swaps(&rep.height, n);
74805b261ecSmrg	swapl(&rep.mode, n);
74905b261ecSmrg	swaps(&rep.rotation, n);
75005b261ecSmrg	swaps(&rep.rotations, n);
75105b261ecSmrg	swaps(&rep.nOutput, n);
75205b261ecSmrg	swaps(&rep.nPossibleOutput, n);
75305b261ecSmrg    }
75405b261ecSmrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
75505b261ecSmrg    if (extraLen)
75605b261ecSmrg    {
75705b261ecSmrg	WriteToClient (client, extraLen, (char *) extra);
7586747b715Smrg	free(extra);
75905b261ecSmrg    }
76005b261ecSmrg
7616747b715Smrg    return Success;
76205b261ecSmrg}
76305b261ecSmrg
76405b261ecSmrgint
76505b261ecSmrgProcRRSetCrtcConfig (ClientPtr client)
76605b261ecSmrg{
76705b261ecSmrg    REQUEST(xRRSetCrtcConfigReq);
76805b261ecSmrg    xRRSetCrtcConfigReply   rep;
76905b261ecSmrg    ScreenPtr		    pScreen;
77005b261ecSmrg    rrScrPrivPtr	    pScrPriv;
77105b261ecSmrg    RRCrtcPtr		    crtc;
77205b261ecSmrg    RRModePtr		    mode;
77305b261ecSmrg    int			    numOutputs;
77405b261ecSmrg    RROutputPtr		    *outputs = NULL;
77505b261ecSmrg    RROutput		    *outputIds;
77605b261ecSmrg    TimeStamp		    configTime;
77705b261ecSmrg    TimeStamp		    time;
77805b261ecSmrg    Rotation		    rotation;
7796747b715Smrg    int			    rc, i, j;
78005b261ecSmrg
78105b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
7826747b715Smrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
78305b261ecSmrg
7846747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
7856747b715Smrg
78605b261ecSmrg    if (stuff->mode == None)
78705b261ecSmrg    {
78805b261ecSmrg	mode = NULL;
78905b261ecSmrg	if (numOutputs > 0)
79005b261ecSmrg	    return BadMatch;
79105b261ecSmrg    }
79205b261ecSmrg    else
79305b261ecSmrg    {
7946747b715Smrg	VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
79505b261ecSmrg	if (numOutputs == 0)
79605b261ecSmrg	    return BadMatch;
79705b261ecSmrg    }
79805b261ecSmrg    if (numOutputs)
79905b261ecSmrg    {
8006747b715Smrg	outputs = malloc(numOutputs * sizeof (RROutputPtr));
80105b261ecSmrg	if (!outputs)
80205b261ecSmrg	    return BadAlloc;
80305b261ecSmrg    }
80405b261ecSmrg    else
80505b261ecSmrg	outputs = NULL;
80605b261ecSmrg
80705b261ecSmrg    outputIds = (RROutput *) (stuff + 1);
80805b261ecSmrg    for (i = 0; i < numOutputs; i++)
80905b261ecSmrg    {
8106747b715Smrg	rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
8116747b715Smrg				     RROutputType, client, DixSetAttrAccess);
8126747b715Smrg	if (rc != Success)
81305b261ecSmrg	{
8146747b715Smrg	    free(outputs);
8156747b715Smrg	    return rc;
81605b261ecSmrg	}
81705b261ecSmrg	/* validate crtc for this output */
81805b261ecSmrg	for (j = 0; j < outputs[i]->numCrtcs; j++)
81905b261ecSmrg	    if (outputs[i]->crtcs[j] == crtc)
82005b261ecSmrg		break;
82105b261ecSmrg	if (j == outputs[i]->numCrtcs)
82205b261ecSmrg	{
8236747b715Smrg	    free(outputs);
82405b261ecSmrg	    return BadMatch;
82505b261ecSmrg	}
82605b261ecSmrg	/* validate mode for this output */
82705b261ecSmrg	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
82805b261ecSmrg	{
82905b261ecSmrg	    RRModePtr	m = (j < outputs[i]->numModes ?
83005b261ecSmrg			     outputs[i]->modes[j] :
83105b261ecSmrg			     outputs[i]->userModes[j - outputs[i]->numModes]);
83205b261ecSmrg	    if (m == mode)
83305b261ecSmrg		break;
83405b261ecSmrg	}
83505b261ecSmrg	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
83605b261ecSmrg	{
8376747b715Smrg	    free(outputs);
83805b261ecSmrg	    return BadMatch;
83905b261ecSmrg	}
84005b261ecSmrg    }
84105b261ecSmrg    /* validate clones */
84205b261ecSmrg    for (i = 0; i < numOutputs; i++)
84305b261ecSmrg    {
84405b261ecSmrg	for (j = 0; j < numOutputs; j++)
84505b261ecSmrg	{
84605b261ecSmrg	    int k;
84705b261ecSmrg	    if (i == j)
84805b261ecSmrg		continue;
84905b261ecSmrg	    for (k = 0; k < outputs[i]->numClones; k++)
85005b261ecSmrg	    {
85105b261ecSmrg		if (outputs[i]->clones[k] == outputs[j])
85205b261ecSmrg		    break;
85305b261ecSmrg	    }
85405b261ecSmrg	    if (k == outputs[i]->numClones)
85505b261ecSmrg	    {
8566747b715Smrg		free(outputs);
85705b261ecSmrg		return BadMatch;
85805b261ecSmrg	    }
85905b261ecSmrg	}
86005b261ecSmrg    }
86105b261ecSmrg
86205b261ecSmrg    pScreen = crtc->pScreen;
86305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
86405b261ecSmrg
86505b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
86605b261ecSmrg    configTime = ClientTimeToServerTime(stuff->configTimestamp);
86705b261ecSmrg
86805b261ecSmrg    if (!pScrPriv)
86905b261ecSmrg    {
87005b261ecSmrg	time = currentTime;
87105b261ecSmrg	rep.status = RRSetConfigFailed;
87205b261ecSmrg	goto sendReply;
87305b261ecSmrg    }
87405b261ecSmrg
87505b261ecSmrg    /*
87605b261ecSmrg     * Validate requested rotation
87705b261ecSmrg     */
87805b261ecSmrg    rotation = (Rotation) stuff->rotation;
87905b261ecSmrg
88005b261ecSmrg    /* test the rotation bits only! */
88105b261ecSmrg    switch (rotation & 0xf) {
88205b261ecSmrg    case RR_Rotate_0:
88305b261ecSmrg    case RR_Rotate_90:
88405b261ecSmrg    case RR_Rotate_180:
88505b261ecSmrg    case RR_Rotate_270:
88605b261ecSmrg	break;
88705b261ecSmrg    default:
88805b261ecSmrg	/*
88905b261ecSmrg	 * Invalid rotation
89005b261ecSmrg	 */
89105b261ecSmrg	client->errorValue = stuff->rotation;
8926747b715Smrg	free(outputs);
89305b261ecSmrg	return BadValue;
89405b261ecSmrg    }
89505b261ecSmrg
89605b261ecSmrg    if (mode)
89705b261ecSmrg    {
89805b261ecSmrg	if ((~crtc->rotations) & rotation)
89905b261ecSmrg	{
90005b261ecSmrg	    /*
90105b261ecSmrg	     * requested rotation or reflection not supported by screen
90205b261ecSmrg	     */
90305b261ecSmrg	    client->errorValue = stuff->rotation;
9046747b715Smrg	    free(outputs);
90505b261ecSmrg	    return BadMatch;
90605b261ecSmrg	}
90705b261ecSmrg
90805b261ecSmrg#ifdef RANDR_12_INTERFACE
90905b261ecSmrg	/*
91005b261ecSmrg	 * Check screen size bounds if the DDX provides a 1.2 interface
91105b261ecSmrg	 * for setting screen size. Else, assume the CrtcSet sets
9124642e01fSmrg	 * the size along with the mode. If the driver supports transforms,
9134642e01fSmrg	 * then it must allow crtcs to display a subset of the screen, so
9144642e01fSmrg	 * only do this check for drivers without transform support.
91505b261ecSmrg	 */
9164642e01fSmrg	if (pScrPriv->rrScreenSetSize && !crtc->transforms)
91705b261ecSmrg	{
9184642e01fSmrg	    int source_width;
9194642e01fSmrg	    int	source_height;
9204642e01fSmrg	    PictTransform transform;
9214642e01fSmrg	    struct pixman_f_transform f_transform, f_inverse;
92205b261ecSmrg
9234642e01fSmrg	    RRTransformCompute (stuff->x, stuff->y,
9244642e01fSmrg				mode->mode.width, mode->mode.height,
9254642e01fSmrg				rotation,
9264642e01fSmrg				&crtc->client_pending_transform,
9274642e01fSmrg				&transform, &f_transform, &f_inverse);
9284642e01fSmrg
9294642e01fSmrg	    RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
93005b261ecSmrg	    if (stuff->x + source_width > pScreen->width)
93105b261ecSmrg	    {
93205b261ecSmrg		client->errorValue = stuff->x;
9336747b715Smrg		free(outputs);
93405b261ecSmrg		return BadValue;
93505b261ecSmrg	    }
93605b261ecSmrg
93705b261ecSmrg	    if (stuff->y + source_height > pScreen->height)
93805b261ecSmrg	    {
93905b261ecSmrg		client->errorValue = stuff->y;
9406747b715Smrg		free(outputs);
94105b261ecSmrg		return BadValue;
94205b261ecSmrg	    }
94305b261ecSmrg	}
94405b261ecSmrg#endif
94505b261ecSmrg    }
94605b261ecSmrg
94705b261ecSmrg    if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
94805b261ecSmrg		   rotation, numOutputs, outputs))
94905b261ecSmrg    {
95005b261ecSmrg	rep.status = RRSetConfigFailed;
95105b261ecSmrg	goto sendReply;
95205b261ecSmrg    }
95305b261ecSmrg    rep.status = RRSetConfigSuccess;
95452397711Smrg    pScrPriv->lastSetTime = time;
95505b261ecSmrg
95605b261ecSmrgsendReply:
9576747b715Smrg    free(outputs);
95805b261ecSmrg
95905b261ecSmrg    rep.type = X_Reply;
96005b261ecSmrg    /* rep.status has already been filled in */
96105b261ecSmrg    rep.length = 0;
96205b261ecSmrg    rep.sequenceNumber = client->sequence;
96352397711Smrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
96405b261ecSmrg
96505b261ecSmrg    if (client->swapped)
96605b261ecSmrg    {
96705b261ecSmrg	int n;
96805b261ecSmrg    	swaps(&rep.sequenceNumber, n);
96905b261ecSmrg    	swapl(&rep.length, n);
97005b261ecSmrg	swapl(&rep.newTimestamp, n);
97105b261ecSmrg    }
97205b261ecSmrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
97305b261ecSmrg
9746747b715Smrg    return Success;
97505b261ecSmrg}
97605b261ecSmrg
9774642e01fSmrgint
9784642e01fSmrgProcRRGetPanning (ClientPtr client)
9794642e01fSmrg{
9804642e01fSmrg    REQUEST(xRRGetPanningReq);
9814642e01fSmrg    xRRGetPanningReply	rep;
9824642e01fSmrg    RRCrtcPtr		crtc;
9834642e01fSmrg    ScreenPtr		pScreen;
9844642e01fSmrg    rrScrPrivPtr	pScrPriv;
9854642e01fSmrg    BoxRec		total;
9864642e01fSmrg    BoxRec		tracking;
9874642e01fSmrg    INT16		border[4];
9884642e01fSmrg    int			n;
9894642e01fSmrg
9904642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
9916747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
9924642e01fSmrg
9934642e01fSmrg    /* All crtcs must be associated with screens before client
9944642e01fSmrg     * requests are processed
9954642e01fSmrg     */
9964642e01fSmrg    pScreen = crtc->pScreen;
9974642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
9984642e01fSmrg
9994642e01fSmrg    if (!pScrPriv)
10004642e01fSmrg	return RRErrorBase + BadRRCrtc;
10014642e01fSmrg
10024642e01fSmrg    memset(&rep, 0, sizeof(rep));
10034642e01fSmrg    rep.type = X_Reply;
10044642e01fSmrg    rep.status = RRSetConfigSuccess;
10054642e01fSmrg    rep.sequenceNumber = client->sequence;
10064642e01fSmrg    rep.length = 1;
10074642e01fSmrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
10084642e01fSmrg
10094642e01fSmrg    if (pScrPriv->rrGetPanning &&
10104642e01fSmrg	pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
10114642e01fSmrg	rep.left          = total.x1;
10124642e01fSmrg	rep.top           = total.y1;
10134642e01fSmrg	rep.width         = total.x2 - total.x1;
10144642e01fSmrg	rep.height        = total.y2 - total.y1;
10154642e01fSmrg	rep.track_left    = tracking.x1;
10164642e01fSmrg	rep.track_top     = tracking.y1;
10174642e01fSmrg	rep.track_width   = tracking.x2 - tracking.x1;
10184642e01fSmrg	rep.track_height  = tracking.y2 - tracking.y1;
10194642e01fSmrg	rep.border_left   = border[0];
10204642e01fSmrg	rep.border_top    = border[1];
10214642e01fSmrg	rep.border_right  = border[2];
10224642e01fSmrg	rep.border_bottom = border[3];
10234642e01fSmrg    }
10244642e01fSmrg
10254642e01fSmrg    if (client->swapped) {
10264642e01fSmrg	swaps(&rep.sequenceNumber, n);
10274642e01fSmrg	swapl(&rep.length, n);
10284642e01fSmrg	swaps(&rep.timestamp, n);
10294642e01fSmrg	swaps(&rep.left, n);
10304642e01fSmrg	swaps(&rep.top, n);
10314642e01fSmrg	swaps(&rep.width, n);
10324642e01fSmrg	swaps(&rep.height, n);
10334642e01fSmrg	swaps(&rep.track_left, n);
10344642e01fSmrg	swaps(&rep.track_top, n);
10354642e01fSmrg	swaps(&rep.track_width, n);
10364642e01fSmrg	swaps(&rep.track_height, n);
10374642e01fSmrg	swaps(&rep.border_left, n);
10384642e01fSmrg	swaps(&rep.border_top, n);
10394642e01fSmrg	swaps(&rep.border_right, n);
10404642e01fSmrg	swaps(&rep.border_bottom, n);
10414642e01fSmrg    }
10424642e01fSmrg    WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
10436747b715Smrg    return Success;
10444642e01fSmrg}
10454642e01fSmrg
10464642e01fSmrgint
10474642e01fSmrgProcRRSetPanning (ClientPtr client)
10484642e01fSmrg{
10494642e01fSmrg    REQUEST(xRRSetPanningReq);
10504642e01fSmrg    xRRSetPanningReply	rep;
10514642e01fSmrg    RRCrtcPtr		crtc;
10524642e01fSmrg    ScreenPtr		pScreen;
10534642e01fSmrg    rrScrPrivPtr	pScrPriv;
10544642e01fSmrg    TimeStamp		time;
10554642e01fSmrg    BoxRec		total;
10564642e01fSmrg    BoxRec		tracking;
10574642e01fSmrg    INT16		border[4];
10584642e01fSmrg    int			n;
10594642e01fSmrg
10604642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
10616747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
10624642e01fSmrg
10634642e01fSmrg    /* All crtcs must be associated with screens before client
10644642e01fSmrg     * requests are processed
10654642e01fSmrg     */
10664642e01fSmrg    pScreen = crtc->pScreen;
10674642e01fSmrg    pScrPriv = rrGetScrPriv(pScreen);
10684642e01fSmrg
10694642e01fSmrg    if (!pScrPriv) {
10704642e01fSmrg	time = currentTime;
10714642e01fSmrg	rep.status = RRSetConfigFailed;
10724642e01fSmrg	goto sendReply;
10734642e01fSmrg    }
10744642e01fSmrg
10754642e01fSmrg    time = ClientTimeToServerTime(stuff->timestamp);
10764642e01fSmrg
10774642e01fSmrg    if (!pScrPriv->rrGetPanning)
10784642e01fSmrg	return RRErrorBase + BadRRCrtc;
10794642e01fSmrg
10804642e01fSmrg    total.x1    = stuff->left;
10814642e01fSmrg    total.y1    = stuff->top;
10824642e01fSmrg    total.x2    = total.x1 + stuff->width;
10834642e01fSmrg    total.y2    = total.y1 + stuff->height;
10844642e01fSmrg    tracking.x1 = stuff->track_left;
10854642e01fSmrg    tracking.y1 = stuff->track_top;
10864642e01fSmrg    tracking.x2 = tracking.x1 + stuff->track_width;
10874642e01fSmrg    tracking.y2 = tracking.y1 + stuff->track_height;
10884642e01fSmrg    border[0]   = stuff->border_left;
10894642e01fSmrg    border[1]   = stuff->border_top;
10904642e01fSmrg    border[2]   = stuff->border_right;
10914642e01fSmrg    border[3]   = stuff->border_bottom;
10924642e01fSmrg
10934642e01fSmrg    if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
10944642e01fSmrg	return BadMatch;
10954642e01fSmrg
109652397711Smrg    pScrPriv->lastSetTime = time;
109752397711Smrg
10984642e01fSmrg    rep.status = RRSetConfigSuccess;
10994642e01fSmrg
11004642e01fSmrgsendReply:
11014642e01fSmrg    rep.type = X_Reply;
11024642e01fSmrg    rep.sequenceNumber = client->sequence;
11034642e01fSmrg    rep.length = 0;
11044642e01fSmrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
11054642e01fSmrg
11064642e01fSmrg    if (client->swapped) {
11074642e01fSmrg	swaps(&rep.sequenceNumber, n);
11084642e01fSmrg	swapl(&rep.length, n);
11094642e01fSmrg	swaps(&rep.newTimestamp, n);
11104642e01fSmrg    }
11114642e01fSmrg    WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
11126747b715Smrg    return Success;
11134642e01fSmrg}
11144642e01fSmrg
111505b261ecSmrgint
111605b261ecSmrgProcRRGetCrtcGammaSize (ClientPtr client)
111705b261ecSmrg{
111805b261ecSmrg    REQUEST(xRRGetCrtcGammaSizeReq);
111905b261ecSmrg    xRRGetCrtcGammaSizeReply	reply;
112005b261ecSmrg    RRCrtcPtr			crtc;
112105b261ecSmrg    int				n;
112205b261ecSmrg
112305b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
11246747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
11256747b715Smrg
11266747b715Smrg    /* Gamma retrieval failed, any better error? */
11276747b715Smrg    if (!RRCrtcGammaGet(crtc))
11286747b715Smrg        return RRErrorBase + BadRRCrtc;
11296747b715Smrg
113005b261ecSmrg    reply.type = X_Reply;
113105b261ecSmrg    reply.sequenceNumber = client->sequence;
113205b261ecSmrg    reply.length = 0;
113305b261ecSmrg    reply.size = crtc->gammaSize;
113405b261ecSmrg    if (client->swapped) {
113505b261ecSmrg	swaps (&reply.sequenceNumber, n);
113605b261ecSmrg	swapl (&reply.length, n);
113705b261ecSmrg	swaps (&reply.size, n);
113805b261ecSmrg    }
113905b261ecSmrg    WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
11406747b715Smrg    return Success;
114105b261ecSmrg}
114205b261ecSmrg
114305b261ecSmrgint
114405b261ecSmrgProcRRGetCrtcGamma (ClientPtr client)
114505b261ecSmrg{
114605b261ecSmrg    REQUEST(xRRGetCrtcGammaReq);
114705b261ecSmrg    xRRGetCrtcGammaReply	reply;
114805b261ecSmrg    RRCrtcPtr			crtc;
114905b261ecSmrg    int				n;
115005b261ecSmrg    unsigned long		len;
11514642e01fSmrg    char			*extra = NULL;
115205b261ecSmrg
115305b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
11546747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
11556747b715Smrg
11566747b715Smrg    /* Gamma retrieval failed, any better error? */
11576747b715Smrg    if (!RRCrtcGammaGet(crtc))
11586747b715Smrg        return RRErrorBase + BadRRCrtc;
11596747b715Smrg
116005b261ecSmrg    len = crtc->gammaSize * 3 * 2;
116105b261ecSmrg
11624642e01fSmrg    if (crtc->gammaSize) {
11636747b715Smrg	extra = malloc(len);
11644642e01fSmrg	if (!extra)
11654642e01fSmrg	    return BadAlloc;
11664642e01fSmrg    }
11674642e01fSmrg
116805b261ecSmrg    reply.type = X_Reply;
116905b261ecSmrg    reply.sequenceNumber = client->sequence;
11706747b715Smrg    reply.length = bytes_to_int32(len);
117105b261ecSmrg    reply.size = crtc->gammaSize;
117205b261ecSmrg    if (client->swapped) {
117305b261ecSmrg	swaps (&reply.sequenceNumber, n);
117405b261ecSmrg	swapl (&reply.length, n);
117505b261ecSmrg	swaps (&reply.size, n);
117605b261ecSmrg    }
117705b261ecSmrg    WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
117805b261ecSmrg    if (crtc->gammaSize)
117905b261ecSmrg    {
11804642e01fSmrg	memcpy(extra, crtc->gammaRed, len);
118105b261ecSmrg	client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
11824642e01fSmrg	WriteSwappedDataToClient (client, len, extra);
11836747b715Smrg	free(extra);
118405b261ecSmrg    }
11856747b715Smrg    return Success;
118605b261ecSmrg}
118705b261ecSmrg
118805b261ecSmrgint
118905b261ecSmrgProcRRSetCrtcGamma (ClientPtr client)
119005b261ecSmrg{
119105b261ecSmrg    REQUEST(xRRSetCrtcGammaReq);
119205b261ecSmrg    RRCrtcPtr			crtc;
119305b261ecSmrg    unsigned long		len;
119405b261ecSmrg    CARD16			*red, *green, *blue;
119505b261ecSmrg
119605b261ecSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
11976747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
119805b261ecSmrg
11996747b715Smrg    len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
120005b261ecSmrg    if (len < (stuff->size * 3 + 1) >> 1)
120105b261ecSmrg	return BadLength;
120205b261ecSmrg
120305b261ecSmrg    if (stuff->size != crtc->gammaSize)
120405b261ecSmrg	return BadMatch;
120505b261ecSmrg
120605b261ecSmrg    red = (CARD16 *) (stuff + 1);
120705b261ecSmrg    green = red + crtc->gammaSize;
120805b261ecSmrg    blue = green + crtc->gammaSize;
120905b261ecSmrg
121005b261ecSmrg    RRCrtcGammaSet (crtc, red, green, blue);
121105b261ecSmrg
121205b261ecSmrg    return Success;
121305b261ecSmrg}
121405b261ecSmrg
12154642e01fSmrg/* Version 1.3 additions */
12164642e01fSmrg
12174642e01fSmrgint
12184642e01fSmrgProcRRSetCrtcTransform (ClientPtr client)
12194642e01fSmrg{
12204642e01fSmrg    REQUEST(xRRSetCrtcTransformReq);
12214642e01fSmrg    RRCrtcPtr		    crtc;
12224642e01fSmrg    PictTransform	    transform;
12234642e01fSmrg    struct pixman_f_transform f_transform, f_inverse;
12244642e01fSmrg    char		    *filter;
12254642e01fSmrg    int			    nbytes;
12264642e01fSmrg    xFixed		    *params;
12274642e01fSmrg    int			    nparams;
12284642e01fSmrg
12294642e01fSmrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
12306747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
12314642e01fSmrg
12324642e01fSmrg    PictTransform_from_xRenderTransform (&transform, &stuff->transform);
12334642e01fSmrg    pixman_f_transform_from_pixman_transform (&f_transform, &transform);
12344642e01fSmrg    if (!pixman_f_transform_invert (&f_inverse, &f_transform))
12354642e01fSmrg	return BadMatch;
12364642e01fSmrg
12374642e01fSmrg    filter = (char *) (stuff + 1);
12384642e01fSmrg    nbytes = stuff->nbytesFilter;
12396747b715Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
12404642e01fSmrg    nparams = ((xFixed *) stuff + client->req_len) - params;
12414642e01fSmrg    if (nparams < 0)
12424642e01fSmrg	return BadLength;
12434642e01fSmrg
12444642e01fSmrg    return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
12454642e01fSmrg			       filter, nbytes, params, nparams);
12464642e01fSmrg}
12474642e01fSmrg
12484642e01fSmrg
12494642e01fSmrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
12504642e01fSmrg
12514642e01fSmrgstatic int
12524642e01fSmrgtransform_filter_length (RRTransformPtr transform)
12534642e01fSmrg{
12544642e01fSmrg    int	nbytes, nparams;
12554642e01fSmrg
12564642e01fSmrg    if (transform->filter == NULL)
12574642e01fSmrg	return 0;
12584642e01fSmrg    nbytes = strlen (transform->filter->name);
12594642e01fSmrg    nparams = transform->nparams;
12606747b715Smrg    return pad_to_int32(nbytes) + (nparams * sizeof (xFixed));
12614642e01fSmrg}
12624642e01fSmrg
12634642e01fSmrgstatic int
12644642e01fSmrgtransform_filter_encode (ClientPtr client, char *output,
12654642e01fSmrg			 CARD16	*nbytesFilter,
12664642e01fSmrg			 CARD16	*nparamsFilter,
12674642e01fSmrg			 RRTransformPtr transform)
12684642e01fSmrg{
12694642e01fSmrg    int	    nbytes, nparams;
12704642e01fSmrg    int	    n;
12714642e01fSmrg
12724642e01fSmrg    if (transform->filter == NULL) {
12734642e01fSmrg	*nbytesFilter = 0;
12744642e01fSmrg	*nparamsFilter = 0;
12754642e01fSmrg	return 0;
12764642e01fSmrg    }
12774642e01fSmrg    nbytes = strlen (transform->filter->name);
12784642e01fSmrg    nparams = transform->nparams;
12794642e01fSmrg    *nbytesFilter = nbytes;
12804642e01fSmrg    *nparamsFilter = nparams;
12814642e01fSmrg    memcpy (output, transform->filter->name, nbytes);
12824642e01fSmrg    while ((nbytes & 3) != 0)
12834642e01fSmrg	output[nbytes++] = 0;
12844642e01fSmrg    memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
12854642e01fSmrg    if (client->swapped) {
12864642e01fSmrg	swaps (nbytesFilter, n);
12874642e01fSmrg	swaps (nparamsFilter, n);
12884642e01fSmrg	SwapLongs ((CARD32 *) (output + nbytes), nparams);
12894642e01fSmrg    }
12904642e01fSmrg    nbytes += nparams * sizeof (xFixed);
12914642e01fSmrg    return nbytes;
12924642e01fSmrg}
12934642e01fSmrg
12944642e01fSmrgstatic void
12954642e01fSmrgtransform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
12964642e01fSmrg{
12974642e01fSmrg    xRenderTransform_from_PictTransform (wire, pict);
12984642e01fSmrg    if (client->swapped)
12996747b715Smrg	SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
13004642e01fSmrg}
13014642e01fSmrg
13024642e01fSmrgint
13034642e01fSmrgProcRRGetCrtcTransform (ClientPtr client)
13044642e01fSmrg{
13054642e01fSmrg    REQUEST(xRRGetCrtcTransformReq);
13064642e01fSmrg    xRRGetCrtcTransformReply	*reply;
13074642e01fSmrg    RRCrtcPtr			crtc;
13084642e01fSmrg    int				n, nextra;
13094642e01fSmrg    RRTransformPtr		current, pending;
13104642e01fSmrg    char			*extra;
13114642e01fSmrg
13124642e01fSmrg    REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
13136747b715Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
13144642e01fSmrg
13154642e01fSmrg    pending = &crtc->client_pending_transform;
13164642e01fSmrg    current = &crtc->client_current_transform;
13174642e01fSmrg
13184642e01fSmrg    nextra = (transform_filter_length (pending) +
13194642e01fSmrg	      transform_filter_length (current));
13204642e01fSmrg
13216747b715Smrg    reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra);
13224642e01fSmrg    if (!reply)
13234642e01fSmrg	return BadAlloc;
13244642e01fSmrg
13254642e01fSmrg    extra = (char *) (reply + 1);
13264642e01fSmrg    reply->type = X_Reply;
13274642e01fSmrg    reply->sequenceNumber = client->sequence;
13286747b715Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
13294642e01fSmrg
13304642e01fSmrg    reply->hasTransforms = crtc->transforms;
13314642e01fSmrg
13324642e01fSmrg    transform_encode (client, &reply->pendingTransform, &pending->transform);
13334642e01fSmrg    extra += transform_filter_encode (client, extra,
13344642e01fSmrg				      &reply->pendingNbytesFilter,
13354642e01fSmrg				      &reply->pendingNparamsFilter,
13364642e01fSmrg				      pending);
13374642e01fSmrg
13384642e01fSmrg    transform_encode (client, &reply->currentTransform, &current->transform);
13394642e01fSmrg    extra += transform_filter_encode (client, extra,
13404642e01fSmrg				      &reply->currentNbytesFilter,
13414642e01fSmrg				      &reply->currentNparamsFilter,
13424642e01fSmrg				      current);
13434642e01fSmrg
13444642e01fSmrg    if (client->swapped) {
13454642e01fSmrg	swaps (&reply->sequenceNumber, n);
13464642e01fSmrg	swapl (&reply->length, n);
13474642e01fSmrg    }
13484642e01fSmrg    WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
13496747b715Smrg    free(reply);
13506747b715Smrg    return Success;
13514642e01fSmrg}
1352