1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include "randrstr.h"
24706f2543Smrg#include "swaprep.h"
25706f2543Smrg
26706f2543SmrgRESTYPE	RRCrtcType;
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Notify the CRTC of some change
30706f2543Smrg */
31706f2543Smrgvoid
32706f2543SmrgRRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
33706f2543Smrg{
34706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
35706f2543Smrg
36706f2543Smrg    crtc->changed = TRUE;
37706f2543Smrg    if (pScreen)
38706f2543Smrg    {
39706f2543Smrg	rrScrPriv(pScreen);
40706f2543Smrg
41706f2543Smrg	pScrPriv->changed = TRUE;
42706f2543Smrg	/*
43706f2543Smrg	 * Send ConfigureNotify on any layout change
44706f2543Smrg	 */
45706f2543Smrg	if (layoutChanged)
46706f2543Smrg	    pScrPriv->layoutChanged = TRUE;
47706f2543Smrg    }
48706f2543Smrg}
49706f2543Smrg
50706f2543Smrg/*
51706f2543Smrg * Create a CRTC
52706f2543Smrg */
53706f2543SmrgRRCrtcPtr
54706f2543SmrgRRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
55706f2543Smrg{
56706f2543Smrg    RRCrtcPtr	    crtc;
57706f2543Smrg    RRCrtcPtr	    *crtcs;
58706f2543Smrg    rrScrPrivPtr    pScrPriv;
59706f2543Smrg
60706f2543Smrg    if (!RRInit())
61706f2543Smrg	return NULL;
62706f2543Smrg
63706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
64706f2543Smrg
65706f2543Smrg    /* make space for the crtc pointer */
66706f2543Smrg    if (pScrPriv->numCrtcs)
67706f2543Smrg	crtcs = realloc(pScrPriv->crtcs,
68706f2543Smrg			  (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
69706f2543Smrg    else
70706f2543Smrg	crtcs = malloc(sizeof (RRCrtcPtr));
71706f2543Smrg    if (!crtcs)
72706f2543Smrg	return FALSE;
73706f2543Smrg    pScrPriv->crtcs = crtcs;
74706f2543Smrg
75706f2543Smrg    crtc = calloc(1, sizeof (RRCrtcRec));
76706f2543Smrg    if (!crtc)
77706f2543Smrg	return NULL;
78706f2543Smrg    crtc->id = FakeClientID (0);
79706f2543Smrg    crtc->pScreen = pScreen;
80706f2543Smrg    crtc->mode = NULL;
81706f2543Smrg    crtc->x = 0;
82706f2543Smrg    crtc->y = 0;
83706f2543Smrg    crtc->rotation = RR_Rotate_0;
84706f2543Smrg    crtc->rotations = RR_Rotate_0;
85706f2543Smrg    crtc->outputs = NULL;
86706f2543Smrg    crtc->numOutputs = 0;
87706f2543Smrg    crtc->gammaSize = 0;
88706f2543Smrg    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
89706f2543Smrg    crtc->changed = FALSE;
90706f2543Smrg    crtc->devPrivate = devPrivate;
91706f2543Smrg    RRTransformInit (&crtc->client_pending_transform);
92706f2543Smrg    RRTransformInit (&crtc->client_current_transform);
93706f2543Smrg    pixman_transform_init_identity (&crtc->transform);
94706f2543Smrg    pixman_f_transform_init_identity (&crtc->f_transform);
95706f2543Smrg    pixman_f_transform_init_identity (&crtc->f_inverse);
96706f2543Smrg
97706f2543Smrg    if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
98706f2543Smrg	return NULL;
99706f2543Smrg
100706f2543Smrg    /* attach the screen and crtc together */
101706f2543Smrg    crtc->pScreen = pScreen;
102706f2543Smrg    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
103706f2543Smrg
104706f2543Smrg    return crtc;
105706f2543Smrg}
106706f2543Smrg
107706f2543Smrg/*
108706f2543Smrg * Set the allowed rotations on a CRTC
109706f2543Smrg */
110706f2543Smrgvoid
111706f2543SmrgRRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
112706f2543Smrg{
113706f2543Smrg    crtc->rotations = rotations;
114706f2543Smrg}
115706f2543Smrg
116706f2543Smrg/*
117706f2543Smrg * Set whether transforms are allowed on a CRTC
118706f2543Smrg */
119706f2543Smrgvoid
120706f2543SmrgRRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
121706f2543Smrg{
122706f2543Smrg    crtc->transforms = transforms;
123706f2543Smrg}
124706f2543Smrg
125706f2543Smrg/*
126706f2543Smrg * Notify the extension that the Crtc has been reconfigured,
127706f2543Smrg * the driver calls this whenever it has updated the mode
128706f2543Smrg */
129706f2543SmrgBool
130706f2543SmrgRRCrtcNotify (RRCrtcPtr	    crtc,
131706f2543Smrg	      RRModePtr	    mode,
132706f2543Smrg	      int	    x,
133706f2543Smrg	      int	    y,
134706f2543Smrg	      Rotation	    rotation,
135706f2543Smrg	      RRTransformPtr transform,
136706f2543Smrg	      int	    numOutputs,
137706f2543Smrg	      RROutputPtr   *outputs)
138706f2543Smrg{
139706f2543Smrg    int	    i, j;
140706f2543Smrg
141706f2543Smrg    /*
142706f2543Smrg     * Check to see if any of the new outputs were
143706f2543Smrg     * not in the old list and mark them as changed
144706f2543Smrg     */
145706f2543Smrg    for (i = 0; i < numOutputs; i++)
146706f2543Smrg    {
147706f2543Smrg	for (j = 0; j < crtc->numOutputs; j++)
148706f2543Smrg	    if (outputs[i] == crtc->outputs[j])
149706f2543Smrg		break;
150706f2543Smrg	if (j == crtc->numOutputs)
151706f2543Smrg	{
152706f2543Smrg	    outputs[i]->crtc = crtc;
153706f2543Smrg	    RROutputChanged (outputs[i], FALSE);
154706f2543Smrg	    RRCrtcChanged (crtc, FALSE);
155706f2543Smrg	}
156706f2543Smrg    }
157706f2543Smrg    /*
158706f2543Smrg     * Check to see if any of the old outputs are
159706f2543Smrg     * not in the new list and mark them as changed
160706f2543Smrg     */
161706f2543Smrg    for (j = 0; j < crtc->numOutputs; j++)
162706f2543Smrg    {
163706f2543Smrg	for (i = 0; i < numOutputs; i++)
164706f2543Smrg	    if (outputs[i] == crtc->outputs[j])
165706f2543Smrg		break;
166706f2543Smrg	if (i == numOutputs)
167706f2543Smrg	{
168706f2543Smrg	    if (crtc->outputs[j]->crtc == crtc)
169706f2543Smrg		crtc->outputs[j]->crtc = NULL;
170706f2543Smrg	    RROutputChanged (crtc->outputs[j], FALSE);
171706f2543Smrg	    RRCrtcChanged (crtc, FALSE);
172706f2543Smrg	}
173706f2543Smrg    }
174706f2543Smrg    /*
175706f2543Smrg     * Reallocate the crtc output array if necessary
176706f2543Smrg     */
177706f2543Smrg    if (numOutputs != crtc->numOutputs)
178706f2543Smrg    {
179706f2543Smrg	RROutputPtr *newoutputs;
180706f2543Smrg
181706f2543Smrg	if (numOutputs)
182706f2543Smrg	{
183706f2543Smrg	    if (crtc->numOutputs)
184706f2543Smrg		newoutputs = realloc(crtc->outputs,
185706f2543Smrg				    numOutputs * sizeof (RROutputPtr));
186706f2543Smrg	    else
187706f2543Smrg		newoutputs = malloc(numOutputs * sizeof (RROutputPtr));
188706f2543Smrg	    if (!newoutputs)
189706f2543Smrg		return FALSE;
190706f2543Smrg	}
191706f2543Smrg	else
192706f2543Smrg	{
193706f2543Smrg	    free(crtc->outputs);
194706f2543Smrg	    newoutputs = NULL;
195706f2543Smrg	}
196706f2543Smrg	crtc->outputs = newoutputs;
197706f2543Smrg	crtc->numOutputs = numOutputs;
198706f2543Smrg    }
199706f2543Smrg    /*
200706f2543Smrg     * Copy the new list of outputs into the crtc
201706f2543Smrg     */
202706f2543Smrg    memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
203706f2543Smrg    /*
204706f2543Smrg     * Update remaining crtc fields
205706f2543Smrg     */
206706f2543Smrg    if (mode != crtc->mode)
207706f2543Smrg    {
208706f2543Smrg	if (crtc->mode)
209706f2543Smrg	    RRModeDestroy (crtc->mode);
210706f2543Smrg	crtc->mode = mode;
211706f2543Smrg	if (mode != NULL)
212706f2543Smrg	    mode->refcnt++;
213706f2543Smrg	RRCrtcChanged (crtc, TRUE);
214706f2543Smrg    }
215706f2543Smrg    if (x != crtc->x)
216706f2543Smrg    {
217706f2543Smrg	crtc->x = x;
218706f2543Smrg	RRCrtcChanged (crtc, TRUE);
219706f2543Smrg    }
220706f2543Smrg    if (y != crtc->y)
221706f2543Smrg    {
222706f2543Smrg	crtc->y = y;
223706f2543Smrg	RRCrtcChanged (crtc, TRUE);
224706f2543Smrg    }
225706f2543Smrg    if (rotation != crtc->rotation)
226706f2543Smrg    {
227706f2543Smrg	crtc->rotation = rotation;
228706f2543Smrg	RRCrtcChanged (crtc, TRUE);
229706f2543Smrg    }
230706f2543Smrg    if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
231706f2543Smrg	RRTransformCopy (&crtc->client_current_transform, transform);
232706f2543Smrg	RRCrtcChanged (crtc, TRUE);
233706f2543Smrg    }
234706f2543Smrg    if (crtc->changed && mode)
235706f2543Smrg    {
236706f2543Smrg	RRTransformCompute (x, y,
237706f2543Smrg			    mode->mode.width, mode->mode.height,
238706f2543Smrg			    rotation,
239706f2543Smrg			    &crtc->client_current_transform,
240706f2543Smrg			    &crtc->transform, &crtc->f_transform,
241706f2543Smrg			    &crtc->f_inverse);
242706f2543Smrg    }
243706f2543Smrg    return TRUE;
244706f2543Smrg}
245706f2543Smrg
246706f2543Smrgvoid
247706f2543SmrgRRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
248706f2543Smrg{
249706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
250706f2543Smrg    rrScrPriv (pScreen);
251706f2543Smrg    xRRCrtcChangeNotifyEvent	ce;
252706f2543Smrg    RRModePtr	mode = crtc->mode;
253706f2543Smrg
254706f2543Smrg    ce.type = RRNotify + RREventBase;
255706f2543Smrg    ce.subCode = RRNotify_CrtcChange;
256706f2543Smrg    ce.timestamp = pScrPriv->lastSetTime.milliseconds;
257706f2543Smrg    ce.window = pWin->drawable.id;
258706f2543Smrg    ce.crtc = crtc->id;
259706f2543Smrg    ce.rotation = crtc->rotation;
260706f2543Smrg    if (mode)
261706f2543Smrg    {
262706f2543Smrg	ce.mode = mode->mode.id;
263706f2543Smrg	ce.x = crtc->x;
264706f2543Smrg	ce.y = crtc->y;
265706f2543Smrg	ce.width = mode->mode.width;
266706f2543Smrg	ce.height = mode->mode.height;
267706f2543Smrg    }
268706f2543Smrg    else
269706f2543Smrg    {
270706f2543Smrg	ce.mode = None;
271706f2543Smrg	ce.x = 0;
272706f2543Smrg	ce.y = 0;
273706f2543Smrg	ce.width = 0;
274706f2543Smrg	ce.height = 0;
275706f2543Smrg    }
276706f2543Smrg    WriteEventsToClient (client, 1, (xEvent *) &ce);
277706f2543Smrg}
278706f2543Smrg
279706f2543Smrgstatic Bool
280706f2543SmrgRRCrtcPendingProperties (RRCrtcPtr crtc)
281706f2543Smrg{
282706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
283706f2543Smrg    rrScrPriv(pScreen);
284706f2543Smrg    int		o;
285706f2543Smrg
286706f2543Smrg    for (o = 0; o < pScrPriv->numOutputs; o++)
287706f2543Smrg    {
288706f2543Smrg	RROutputPtr output = pScrPriv->outputs[o];
289706f2543Smrg	if (output->crtc == crtc && output->pendingProperties)
290706f2543Smrg	    return TRUE;
291706f2543Smrg    }
292706f2543Smrg    return FALSE;
293706f2543Smrg}
294706f2543Smrg
295706f2543Smrg/*
296706f2543Smrg * Request that the Crtc be reconfigured
297706f2543Smrg */
298706f2543SmrgBool
299706f2543SmrgRRCrtcSet (RRCrtcPtr    crtc,
300706f2543Smrg	   RRModePtr	mode,
301706f2543Smrg	   int		x,
302706f2543Smrg	   int		y,
303706f2543Smrg	   Rotation	rotation,
304706f2543Smrg	   int		numOutputs,
305706f2543Smrg	   RROutputPtr  *outputs)
306706f2543Smrg{
307706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
308706f2543Smrg    Bool	ret = FALSE;
309706f2543Smrg    rrScrPriv(pScreen);
310706f2543Smrg
311706f2543Smrg    /* See if nothing changed */
312706f2543Smrg    if (crtc->mode == mode &&
313706f2543Smrg	crtc->x == x &&
314706f2543Smrg	crtc->y == y &&
315706f2543Smrg	crtc->rotation == rotation &&
316706f2543Smrg	crtc->numOutputs == numOutputs &&
317706f2543Smrg	!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
318706f2543Smrg	!RRCrtcPendingProperties (crtc) &&
319706f2543Smrg	!RRCrtcPendingTransform (crtc))
320706f2543Smrg    {
321706f2543Smrg	ret = TRUE;
322706f2543Smrg    }
323706f2543Smrg    else
324706f2543Smrg    {
325706f2543Smrg#if RANDR_12_INTERFACE
326706f2543Smrg	if (pScrPriv->rrCrtcSet)
327706f2543Smrg	{
328706f2543Smrg	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
329706f2543Smrg					  rotation, numOutputs, outputs);
330706f2543Smrg	}
331706f2543Smrg	else
332706f2543Smrg#endif
333706f2543Smrg	{
334706f2543Smrg#if RANDR_10_INTERFACE
335706f2543Smrg	    if (pScrPriv->rrSetConfig)
336706f2543Smrg	    {
337706f2543Smrg		RRScreenSize	    size;
338706f2543Smrg		RRScreenRate	    rate;
339706f2543Smrg
340706f2543Smrg		if (!mode)
341706f2543Smrg		{
342706f2543Smrg		    RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
343706f2543Smrg		    ret = TRUE;
344706f2543Smrg		}
345706f2543Smrg		else
346706f2543Smrg		{
347706f2543Smrg		    size.width = mode->mode.width;
348706f2543Smrg		    size.height = mode->mode.height;
349706f2543Smrg		    if (outputs[0]->mmWidth && outputs[0]->mmHeight)
350706f2543Smrg		    {
351706f2543Smrg			size.mmWidth = outputs[0]->mmWidth;
352706f2543Smrg			size.mmHeight = outputs[0]->mmHeight;
353706f2543Smrg		    }
354706f2543Smrg		    else
355706f2543Smrg		    {
356706f2543Smrg			size.mmWidth = pScreen->mmWidth;
357706f2543Smrg			size.mmHeight = pScreen->mmHeight;
358706f2543Smrg		    }
359706f2543Smrg		    size.nRates = 1;
360706f2543Smrg		    rate.rate = RRVerticalRefresh (&mode->mode);
361706f2543Smrg		    size.pRates = &rate;
362706f2543Smrg		    ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
363706f2543Smrg		    /*
364706f2543Smrg		     * Old 1.0 interface tied screen size to mode size
365706f2543Smrg		     */
366706f2543Smrg		    if (ret)
367706f2543Smrg		    {
368706f2543Smrg			RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
369706f2543Smrg			RRScreenSizeNotify (pScreen);
370706f2543Smrg		    }
371706f2543Smrg		}
372706f2543Smrg	    }
373706f2543Smrg#endif
374706f2543Smrg	}
375706f2543Smrg	if (ret)
376706f2543Smrg	{
377706f2543Smrg	    int	o;
378706f2543Smrg	    RRTellChanged (pScreen);
379706f2543Smrg
380706f2543Smrg	    for (o = 0; o < numOutputs; o++)
381706f2543Smrg		RRPostPendingProperties (outputs[o]);
382706f2543Smrg	}
383706f2543Smrg    }
384706f2543Smrg    return ret;
385706f2543Smrg}
386706f2543Smrg
387706f2543Smrg/*
388706f2543Smrg * Return crtc transform
389706f2543Smrg */
390706f2543SmrgRRTransformPtr
391706f2543SmrgRRCrtcGetTransform (RRCrtcPtr crtc)
392706f2543Smrg{
393706f2543Smrg    RRTransformPtr  transform = &crtc->client_pending_transform;
394706f2543Smrg
395706f2543Smrg    if (pixman_transform_is_identity (&transform->transform))
396706f2543Smrg	return NULL;
397706f2543Smrg    return transform;
398706f2543Smrg}
399706f2543Smrg
400706f2543Smrg/*
401706f2543Smrg * Check whether the pending and current transforms are the same
402706f2543Smrg */
403706f2543SmrgBool
404706f2543SmrgRRCrtcPendingTransform (RRCrtcPtr crtc)
405706f2543Smrg{
406706f2543Smrg    return memcmp (&crtc->client_current_transform.transform,
407706f2543Smrg		   &crtc->client_pending_transform.transform,
408706f2543Smrg		   sizeof (PictTransform)) != 0;
409706f2543Smrg}
410706f2543Smrg
411706f2543Smrg/*
412706f2543Smrg * Destroy a Crtc at shutdown
413706f2543Smrg */
414706f2543Smrgvoid
415706f2543SmrgRRCrtcDestroy (RRCrtcPtr crtc)
416706f2543Smrg{
417706f2543Smrg    FreeResource (crtc->id, 0);
418706f2543Smrg}
419706f2543Smrg
420706f2543Smrgstatic int
421706f2543SmrgRRCrtcDestroyResource (pointer value, XID pid)
422706f2543Smrg{
423706f2543Smrg    RRCrtcPtr	crtc = (RRCrtcPtr) value;
424706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
425706f2543Smrg
426706f2543Smrg    if (pScreen)
427706f2543Smrg    {
428706f2543Smrg	rrScrPriv(pScreen);
429706f2543Smrg	int		i;
430706f2543Smrg
431706f2543Smrg	for (i = 0; i < pScrPriv->numCrtcs; i++)
432706f2543Smrg	{
433706f2543Smrg	    if (pScrPriv->crtcs[i] == crtc)
434706f2543Smrg	    {
435706f2543Smrg		memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
436706f2543Smrg			 (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
437706f2543Smrg		--pScrPriv->numCrtcs;
438706f2543Smrg		break;
439706f2543Smrg	    }
440706f2543Smrg	}
441706f2543Smrg    }
442706f2543Smrg    free(crtc->gammaRed);
443706f2543Smrg    if (crtc->mode)
444706f2543Smrg	RRModeDestroy (crtc->mode);
445706f2543Smrg    free(crtc);
446706f2543Smrg    return 1;
447706f2543Smrg}
448706f2543Smrg
449706f2543Smrg/*
450706f2543Smrg * Request that the Crtc gamma be changed
451706f2543Smrg */
452706f2543Smrg
453706f2543SmrgBool
454706f2543SmrgRRCrtcGammaSet (RRCrtcPtr   crtc,
455706f2543Smrg		CARD16	    *red,
456706f2543Smrg		CARD16	    *green,
457706f2543Smrg		CARD16	    *blue)
458706f2543Smrg{
459706f2543Smrg    Bool	ret = TRUE;
460706f2543Smrg#if RANDR_12_INTERFACE
461706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
462706f2543Smrg#endif
463706f2543Smrg
464706f2543Smrg    memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
465706f2543Smrg    memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
466706f2543Smrg    memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
467706f2543Smrg#if RANDR_12_INTERFACE
468706f2543Smrg    if (pScreen)
469706f2543Smrg    {
470706f2543Smrg	rrScrPriv(pScreen);
471706f2543Smrg	if (pScrPriv->rrCrtcSetGamma)
472706f2543Smrg	    ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
473706f2543Smrg    }
474706f2543Smrg#endif
475706f2543Smrg    return ret;
476706f2543Smrg}
477706f2543Smrg
478706f2543Smrg/*
479706f2543Smrg * Request current gamma back from the DDX (if possible).
480706f2543Smrg * This includes gamma size.
481706f2543Smrg */
482706f2543SmrgBool
483706f2543SmrgRRCrtcGammaGet(RRCrtcPtr crtc)
484706f2543Smrg{
485706f2543Smrg    Bool ret = TRUE;
486706f2543Smrg#if RANDR_12_INTERFACE
487706f2543Smrg    ScreenPtr	pScreen = crtc->pScreen;
488706f2543Smrg#endif
489706f2543Smrg
490706f2543Smrg#if RANDR_12_INTERFACE
491706f2543Smrg    if (pScreen)
492706f2543Smrg    {
493706f2543Smrg        rrScrPriv(pScreen);
494706f2543Smrg        if (pScrPriv->rrCrtcGetGamma)
495706f2543Smrg            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
496706f2543Smrg    }
497706f2543Smrg#endif
498706f2543Smrg    return ret;
499706f2543Smrg}
500706f2543Smrg
501706f2543Smrg/*
502706f2543Smrg * Notify the extension that the Crtc gamma has been changed
503706f2543Smrg * The driver calls this whenever it has changed the gamma values
504706f2543Smrg * in the RRCrtcRec
505706f2543Smrg */
506706f2543Smrg
507706f2543SmrgBool
508706f2543SmrgRRCrtcGammaNotify (RRCrtcPtr	crtc)
509706f2543Smrg{
510706f2543Smrg    return TRUE;    /* not much going on here */
511706f2543Smrg}
512706f2543Smrg
513706f2543Smrgstatic void
514706f2543SmrgRRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
515706f2543Smrg		      int *width, int *height)
516706f2543Smrg{
517706f2543Smrg    BoxRec  box;
518706f2543Smrg
519706f2543Smrg    if (mode == NULL) {
520706f2543Smrg	*width = 0;
521706f2543Smrg	*height = 0;
522706f2543Smrg	return;
523706f2543Smrg    }
524706f2543Smrg
525706f2543Smrg    box.x1 = 0;
526706f2543Smrg    box.y1 = 0;
527706f2543Smrg    box.x2 = mode->mode.width;
528706f2543Smrg    box.y2 = mode->mode.height;
529706f2543Smrg
530706f2543Smrg    pixman_transform_bounds (transform, &box);
531706f2543Smrg    *width = box.x2 - box.x1;
532706f2543Smrg    *height = box.y2 - box.y1;
533706f2543Smrg}
534706f2543Smrg
535706f2543Smrg/**
536706f2543Smrg * Returns the width/height that the crtc scans out from the framebuffer
537706f2543Smrg */
538706f2543Smrgvoid
539706f2543SmrgRRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
540706f2543Smrg{
541706f2543Smrg    RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
542706f2543Smrg}
543706f2543Smrg
544706f2543Smrg/*
545706f2543Smrg * Set the size of the gamma table at server startup time
546706f2543Smrg */
547706f2543Smrg
548706f2543SmrgBool
549706f2543SmrgRRCrtcGammaSetSize (RRCrtcPtr	crtc,
550706f2543Smrg		    int		size)
551706f2543Smrg{
552706f2543Smrg    CARD16  *gamma;
553706f2543Smrg
554706f2543Smrg    if (size == crtc->gammaSize)
555706f2543Smrg	return TRUE;
556706f2543Smrg    if (size)
557706f2543Smrg    {
558706f2543Smrg	gamma = malloc(size * 3 * sizeof (CARD16));
559706f2543Smrg	if (!gamma)
560706f2543Smrg	    return FALSE;
561706f2543Smrg    }
562706f2543Smrg    else
563706f2543Smrg	gamma = NULL;
564706f2543Smrg    free(crtc->gammaRed);
565706f2543Smrg    crtc->gammaRed = gamma;
566706f2543Smrg    crtc->gammaGreen = gamma + size;
567706f2543Smrg    crtc->gammaBlue = gamma + size*2;
568706f2543Smrg    crtc->gammaSize = size;
569706f2543Smrg    return TRUE;
570706f2543Smrg}
571706f2543Smrg
572706f2543Smrg/*
573706f2543Smrg * Set the pending CRTC transformation
574706f2543Smrg */
575706f2543Smrg
576706f2543Smrgint
577706f2543SmrgRRCrtcTransformSet (RRCrtcPtr		crtc,
578706f2543Smrg		    PictTransformPtr	transform,
579706f2543Smrg		    struct pixman_f_transform *f_transform,
580706f2543Smrg		    struct pixman_f_transform *f_inverse,
581706f2543Smrg		    char		*filter_name,
582706f2543Smrg		    int			filter_len,
583706f2543Smrg		    xFixed		*params,
584706f2543Smrg		    int			nparams)
585706f2543Smrg{
586706f2543Smrg    PictFilterPtr   filter = NULL;
587706f2543Smrg    int		    width = 0, height = 0;
588706f2543Smrg
589706f2543Smrg    if (!crtc->transforms)
590706f2543Smrg	return BadValue;
591706f2543Smrg
592706f2543Smrg    if (filter_len)
593706f2543Smrg    {
594706f2543Smrg	filter = PictureFindFilter (crtc->pScreen,
595706f2543Smrg				    filter_name,
596706f2543Smrg				    filter_len);
597706f2543Smrg	if (!filter)
598706f2543Smrg	    return BadName;
599706f2543Smrg	if (filter->ValidateParams)
600706f2543Smrg	{
601706f2543Smrg	    if (!filter->ValidateParams (crtc->pScreen, filter->id,
602706f2543Smrg					 params, nparams, &width, &height))
603706f2543Smrg		return BadMatch;
604706f2543Smrg	}
605706f2543Smrg	else {
606706f2543Smrg	    width = filter->width;
607706f2543Smrg	    height = filter->height;
608706f2543Smrg	}
609706f2543Smrg    }
610706f2543Smrg    else
611706f2543Smrg    {
612706f2543Smrg	if (nparams)
613706f2543Smrg	    return BadMatch;
614706f2543Smrg    }
615706f2543Smrg    if (!RRTransformSetFilter (&crtc->client_pending_transform,
616706f2543Smrg			       filter, params, nparams, width, height))
617706f2543Smrg	return BadAlloc;
618706f2543Smrg
619706f2543Smrg    crtc->client_pending_transform.transform = *transform;
620706f2543Smrg    crtc->client_pending_transform.f_transform = *f_transform;
621706f2543Smrg    crtc->client_pending_transform.f_inverse = *f_inverse;
622706f2543Smrg    return Success;
623706f2543Smrg}
624706f2543Smrg
625706f2543Smrg/*
626706f2543Smrg * Initialize crtc type
627706f2543Smrg */
628706f2543SmrgBool
629706f2543SmrgRRCrtcInit (void)
630706f2543Smrg{
631706f2543Smrg    RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
632706f2543Smrg    if (!RRCrtcType)
633706f2543Smrg	return FALSE;
634706f2543Smrg
635706f2543Smrg    return TRUE;
636706f2543Smrg}
637706f2543Smrg
638706f2543Smrg/*
639706f2543Smrg * Initialize crtc type error value
640706f2543Smrg */
641706f2543Smrgvoid
642706f2543SmrgRRCrtcInitErrorValue(void)
643706f2543Smrg{
644706f2543Smrg    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
645706f2543Smrg}
646706f2543Smrg
647706f2543Smrgint
648706f2543SmrgProcRRGetCrtcInfo (ClientPtr client)
649706f2543Smrg{
650706f2543Smrg    REQUEST(xRRGetCrtcInfoReq);
651706f2543Smrg    xRRGetCrtcInfoReply	rep;
652706f2543Smrg    RRCrtcPtr			crtc;
653706f2543Smrg    CARD8			*extra;
654706f2543Smrg    unsigned long		extraLen;
655706f2543Smrg    ScreenPtr			pScreen;
656706f2543Smrg    rrScrPrivPtr		pScrPriv;
657706f2543Smrg    RRModePtr			mode;
658706f2543Smrg    RROutput			*outputs;
659706f2543Smrg    RROutput			*possible;
660706f2543Smrg    int				i, j, k, n;
661706f2543Smrg    int				width, height;
662706f2543Smrg    BoxRec			panned_area;
663706f2543Smrg
664706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
665706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
666706f2543Smrg
667706f2543Smrg    /* All crtcs must be associated with screens before client
668706f2543Smrg     * requests are processed
669706f2543Smrg     */
670706f2543Smrg    pScreen = crtc->pScreen;
671706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
672706f2543Smrg
673706f2543Smrg    mode = crtc->mode;
674706f2543Smrg
675706f2543Smrg    rep.type = X_Reply;
676706f2543Smrg    rep.status = RRSetConfigSuccess;
677706f2543Smrg    rep.sequenceNumber = client->sequence;
678706f2543Smrg    rep.length = 0;
679706f2543Smrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
680706f2543Smrg    if (pScrPriv->rrGetPanning &&
681706f2543Smrg	pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
682706f2543Smrg	(panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
683706f2543Smrg    {
684706f2543Smrg 	rep.x = panned_area.x1;
685706f2543Smrg	rep.y = panned_area.y1;
686706f2543Smrg	rep.width = panned_area.x2 - panned_area.x1;
687706f2543Smrg	rep.height = panned_area.y2 - panned_area.y1;
688706f2543Smrg    }
689706f2543Smrg    else
690706f2543Smrg    {
691706f2543Smrg	RRCrtcGetScanoutSize (crtc, &width, &height);
692706f2543Smrg	rep.x = crtc->x;
693706f2543Smrg	rep.y = crtc->y;
694706f2543Smrg	rep.width = width;
695706f2543Smrg	rep.height = height;
696706f2543Smrg    }
697706f2543Smrg    rep.mode = mode ? mode->mode.id : 0;
698706f2543Smrg    rep.rotation = crtc->rotation;
699706f2543Smrg    rep.rotations = crtc->rotations;
700706f2543Smrg    rep.nOutput = crtc->numOutputs;
701706f2543Smrg    k = 0;
702706f2543Smrg    for (i = 0; i < pScrPriv->numOutputs; i++)
703706f2543Smrg	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
704706f2543Smrg	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
705706f2543Smrg		k++;
706706f2543Smrg    rep.nPossibleOutput = k;
707706f2543Smrg
708706f2543Smrg    rep.length = rep.nOutput + rep.nPossibleOutput;
709706f2543Smrg
710706f2543Smrg    extraLen = rep.length << 2;
711706f2543Smrg    if (extraLen)
712706f2543Smrg    {
713706f2543Smrg	extra = malloc(extraLen);
714706f2543Smrg	if (!extra)
715706f2543Smrg	    return BadAlloc;
716706f2543Smrg    }
717706f2543Smrg    else
718706f2543Smrg	extra = NULL;
719706f2543Smrg
720706f2543Smrg    outputs = (RROutput *) extra;
721706f2543Smrg    possible = (RROutput *) (outputs + rep.nOutput);
722706f2543Smrg
723706f2543Smrg    for (i = 0; i < crtc->numOutputs; i++)
724706f2543Smrg    {
725706f2543Smrg	outputs[i] = crtc->outputs[i]->id;
726706f2543Smrg	if (client->swapped)
727706f2543Smrg	    swapl (&outputs[i], n);
728706f2543Smrg    }
729706f2543Smrg    k = 0;
730706f2543Smrg    for (i = 0; i < pScrPriv->numOutputs; i++)
731706f2543Smrg	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
732706f2543Smrg	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
733706f2543Smrg	    {
734706f2543Smrg		possible[k] = pScrPriv->outputs[i]->id;
735706f2543Smrg		if (client->swapped)
736706f2543Smrg		    swapl (&possible[k], n);
737706f2543Smrg		k++;
738706f2543Smrg	    }
739706f2543Smrg
740706f2543Smrg    if (client->swapped) {
741706f2543Smrg	swaps(&rep.sequenceNumber, n);
742706f2543Smrg	swapl(&rep.length, n);
743706f2543Smrg	swapl(&rep.timestamp, n);
744706f2543Smrg	swaps(&rep.x, n);
745706f2543Smrg	swaps(&rep.y, n);
746706f2543Smrg	swaps(&rep.width, n);
747706f2543Smrg	swaps(&rep.height, n);
748706f2543Smrg	swapl(&rep.mode, n);
749706f2543Smrg	swaps(&rep.rotation, n);
750706f2543Smrg	swaps(&rep.rotations, n);
751706f2543Smrg	swaps(&rep.nOutput, n);
752706f2543Smrg	swaps(&rep.nPossibleOutput, n);
753706f2543Smrg    }
754706f2543Smrg    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
755706f2543Smrg    if (extraLen)
756706f2543Smrg    {
757706f2543Smrg	WriteToClient (client, extraLen, (char *) extra);
758706f2543Smrg	free(extra);
759706f2543Smrg    }
760706f2543Smrg
761706f2543Smrg    return Success;
762706f2543Smrg}
763706f2543Smrg
764706f2543Smrgint
765706f2543SmrgProcRRSetCrtcConfig (ClientPtr client)
766706f2543Smrg{
767706f2543Smrg    REQUEST(xRRSetCrtcConfigReq);
768706f2543Smrg    xRRSetCrtcConfigReply   rep;
769706f2543Smrg    ScreenPtr		    pScreen;
770706f2543Smrg    rrScrPrivPtr	    pScrPriv;
771706f2543Smrg    RRCrtcPtr		    crtc;
772706f2543Smrg    RRModePtr		    mode;
773706f2543Smrg    int			    numOutputs;
774706f2543Smrg    RROutputPtr		    *outputs = NULL;
775706f2543Smrg    RROutput		    *outputIds;
776706f2543Smrg    TimeStamp		    configTime;
777706f2543Smrg    TimeStamp		    time;
778706f2543Smrg    Rotation		    rotation;
779706f2543Smrg    int			    rc, i, j;
780706f2543Smrg
781706f2543Smrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
782706f2543Smrg    numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
783706f2543Smrg
784706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
785706f2543Smrg
786706f2543Smrg    if (stuff->mode == None)
787706f2543Smrg    {
788706f2543Smrg	mode = NULL;
789706f2543Smrg	if (numOutputs > 0)
790706f2543Smrg	    return BadMatch;
791706f2543Smrg    }
792706f2543Smrg    else
793706f2543Smrg    {
794706f2543Smrg	VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
795706f2543Smrg	if (numOutputs == 0)
796706f2543Smrg	    return BadMatch;
797706f2543Smrg    }
798706f2543Smrg    if (numOutputs)
799706f2543Smrg    {
800706f2543Smrg	outputs = malloc(numOutputs * sizeof (RROutputPtr));
801706f2543Smrg	if (!outputs)
802706f2543Smrg	    return BadAlloc;
803706f2543Smrg    }
804706f2543Smrg    else
805706f2543Smrg	outputs = NULL;
806706f2543Smrg
807706f2543Smrg    outputIds = (RROutput *) (stuff + 1);
808706f2543Smrg    for (i = 0; i < numOutputs; i++)
809706f2543Smrg    {
810706f2543Smrg	rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
811706f2543Smrg				     RROutputType, client, DixSetAttrAccess);
812706f2543Smrg	if (rc != Success)
813706f2543Smrg	{
814706f2543Smrg	    free(outputs);
815706f2543Smrg	    return rc;
816706f2543Smrg	}
817706f2543Smrg	/* validate crtc for this output */
818706f2543Smrg	for (j = 0; j < outputs[i]->numCrtcs; j++)
819706f2543Smrg	    if (outputs[i]->crtcs[j] == crtc)
820706f2543Smrg		break;
821706f2543Smrg	if (j == outputs[i]->numCrtcs)
822706f2543Smrg	{
823706f2543Smrg	    free(outputs);
824706f2543Smrg	    return BadMatch;
825706f2543Smrg	}
826706f2543Smrg	/* validate mode for this output */
827706f2543Smrg	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
828706f2543Smrg	{
829706f2543Smrg	    RRModePtr	m = (j < outputs[i]->numModes ?
830706f2543Smrg			     outputs[i]->modes[j] :
831706f2543Smrg			     outputs[i]->userModes[j - outputs[i]->numModes]);
832706f2543Smrg	    if (m == mode)
833706f2543Smrg		break;
834706f2543Smrg	}
835706f2543Smrg	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
836706f2543Smrg	{
837706f2543Smrg	    free(outputs);
838706f2543Smrg	    return BadMatch;
839706f2543Smrg	}
840706f2543Smrg    }
841706f2543Smrg    /* validate clones */
842706f2543Smrg    for (i = 0; i < numOutputs; i++)
843706f2543Smrg    {
844706f2543Smrg	for (j = 0; j < numOutputs; j++)
845706f2543Smrg	{
846706f2543Smrg	    int k;
847706f2543Smrg	    if (i == j)
848706f2543Smrg		continue;
849706f2543Smrg	    for (k = 0; k < outputs[i]->numClones; k++)
850706f2543Smrg	    {
851706f2543Smrg		if (outputs[i]->clones[k] == outputs[j])
852706f2543Smrg		    break;
853706f2543Smrg	    }
854706f2543Smrg	    if (k == outputs[i]->numClones)
855706f2543Smrg	    {
856706f2543Smrg		free(outputs);
857706f2543Smrg		return BadMatch;
858706f2543Smrg	    }
859706f2543Smrg	}
860706f2543Smrg    }
861706f2543Smrg
862706f2543Smrg    pScreen = crtc->pScreen;
863706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
864706f2543Smrg
865706f2543Smrg    time = ClientTimeToServerTime(stuff->timestamp);
866706f2543Smrg    configTime = ClientTimeToServerTime(stuff->configTimestamp);
867706f2543Smrg
868706f2543Smrg    if (!pScrPriv)
869706f2543Smrg    {
870706f2543Smrg	time = currentTime;
871706f2543Smrg	rep.status = RRSetConfigFailed;
872706f2543Smrg	goto sendReply;
873706f2543Smrg    }
874706f2543Smrg
875706f2543Smrg    /*
876706f2543Smrg     * Validate requested rotation
877706f2543Smrg     */
878706f2543Smrg    rotation = (Rotation) stuff->rotation;
879706f2543Smrg
880706f2543Smrg    /* test the rotation bits only! */
881706f2543Smrg    switch (rotation & 0xf) {
882706f2543Smrg    case RR_Rotate_0:
883706f2543Smrg    case RR_Rotate_90:
884706f2543Smrg    case RR_Rotate_180:
885706f2543Smrg    case RR_Rotate_270:
886706f2543Smrg	break;
887706f2543Smrg    default:
888706f2543Smrg	/*
889706f2543Smrg	 * Invalid rotation
890706f2543Smrg	 */
891706f2543Smrg	client->errorValue = stuff->rotation;
892706f2543Smrg	free(outputs);
893706f2543Smrg	return BadValue;
894706f2543Smrg    }
895706f2543Smrg
896706f2543Smrg    if (mode)
897706f2543Smrg    {
898706f2543Smrg	if ((~crtc->rotations) & rotation)
899706f2543Smrg	{
900706f2543Smrg	    /*
901706f2543Smrg	     * requested rotation or reflection not supported by screen
902706f2543Smrg	     */
903706f2543Smrg	    client->errorValue = stuff->rotation;
904706f2543Smrg	    free(outputs);
905706f2543Smrg	    return BadMatch;
906706f2543Smrg	}
907706f2543Smrg
908706f2543Smrg#ifdef RANDR_12_INTERFACE
909706f2543Smrg	/*
910706f2543Smrg	 * Check screen size bounds if the DDX provides a 1.2 interface
911706f2543Smrg	 * for setting screen size. Else, assume the CrtcSet sets
912706f2543Smrg	 * the size along with the mode. If the driver supports transforms,
913706f2543Smrg	 * then it must allow crtcs to display a subset of the screen, so
914706f2543Smrg	 * only do this check for drivers without transform support.
915706f2543Smrg	 */
916706f2543Smrg	if (pScrPriv->rrScreenSetSize && !crtc->transforms)
917706f2543Smrg	{
918706f2543Smrg	    int source_width;
919706f2543Smrg	    int	source_height;
920706f2543Smrg	    PictTransform transform;
921706f2543Smrg	    struct pixman_f_transform f_transform, f_inverse;
922706f2543Smrg
923706f2543Smrg	    RRTransformCompute (stuff->x, stuff->y,
924706f2543Smrg				mode->mode.width, mode->mode.height,
925706f2543Smrg				rotation,
926706f2543Smrg				&crtc->client_pending_transform,
927706f2543Smrg				&transform, &f_transform, &f_inverse);
928706f2543Smrg
929706f2543Smrg	    RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
930706f2543Smrg	    if (stuff->x + source_width > pScreen->width)
931706f2543Smrg	    {
932706f2543Smrg		client->errorValue = stuff->x;
933706f2543Smrg		free(outputs);
934706f2543Smrg		return BadValue;
935706f2543Smrg	    }
936706f2543Smrg
937706f2543Smrg	    if (stuff->y + source_height > pScreen->height)
938706f2543Smrg	    {
939706f2543Smrg		client->errorValue = stuff->y;
940706f2543Smrg		free(outputs);
941706f2543Smrg		return BadValue;
942706f2543Smrg	    }
943706f2543Smrg	}
944706f2543Smrg#endif
945706f2543Smrg    }
946706f2543Smrg
947706f2543Smrg    if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
948706f2543Smrg		   rotation, numOutputs, outputs))
949706f2543Smrg    {
950706f2543Smrg	rep.status = RRSetConfigFailed;
951706f2543Smrg	goto sendReply;
952706f2543Smrg    }
953706f2543Smrg    rep.status = RRSetConfigSuccess;
954706f2543Smrg    pScrPriv->lastSetTime = time;
955706f2543Smrg
956706f2543SmrgsendReply:
957706f2543Smrg    free(outputs);
958706f2543Smrg
959706f2543Smrg    rep.type = X_Reply;
960706f2543Smrg    /* rep.status has already been filled in */
961706f2543Smrg    rep.length = 0;
962706f2543Smrg    rep.sequenceNumber = client->sequence;
963706f2543Smrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
964706f2543Smrg
965706f2543Smrg    if (client->swapped)
966706f2543Smrg    {
967706f2543Smrg	int n;
968706f2543Smrg    	swaps(&rep.sequenceNumber, n);
969706f2543Smrg    	swapl(&rep.length, n);
970706f2543Smrg	swapl(&rep.newTimestamp, n);
971706f2543Smrg    }
972706f2543Smrg    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
973706f2543Smrg
974706f2543Smrg    return Success;
975706f2543Smrg}
976706f2543Smrg
977706f2543Smrgint
978706f2543SmrgProcRRGetPanning (ClientPtr client)
979706f2543Smrg{
980706f2543Smrg    REQUEST(xRRGetPanningReq);
981706f2543Smrg    xRRGetPanningReply	rep;
982706f2543Smrg    RRCrtcPtr		crtc;
983706f2543Smrg    ScreenPtr		pScreen;
984706f2543Smrg    rrScrPrivPtr	pScrPriv;
985706f2543Smrg    BoxRec		total;
986706f2543Smrg    BoxRec		tracking;
987706f2543Smrg    INT16		border[4];
988706f2543Smrg    int			n;
989706f2543Smrg
990706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetPanningReq);
991706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
992706f2543Smrg
993706f2543Smrg    /* All crtcs must be associated with screens before client
994706f2543Smrg     * requests are processed
995706f2543Smrg     */
996706f2543Smrg    pScreen = crtc->pScreen;
997706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
998706f2543Smrg
999706f2543Smrg    if (!pScrPriv)
1000706f2543Smrg	return RRErrorBase + BadRRCrtc;
1001706f2543Smrg
1002706f2543Smrg    memset(&rep, 0, sizeof(rep));
1003706f2543Smrg    rep.type = X_Reply;
1004706f2543Smrg    rep.status = RRSetConfigSuccess;
1005706f2543Smrg    rep.sequenceNumber = client->sequence;
1006706f2543Smrg    rep.length = 1;
1007706f2543Smrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
1008706f2543Smrg
1009706f2543Smrg    if (pScrPriv->rrGetPanning &&
1010706f2543Smrg	pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
1011706f2543Smrg	rep.left          = total.x1;
1012706f2543Smrg	rep.top           = total.y1;
1013706f2543Smrg	rep.width         = total.x2 - total.x1;
1014706f2543Smrg	rep.height        = total.y2 - total.y1;
1015706f2543Smrg	rep.track_left    = tracking.x1;
1016706f2543Smrg	rep.track_top     = tracking.y1;
1017706f2543Smrg	rep.track_width   = tracking.x2 - tracking.x1;
1018706f2543Smrg	rep.track_height  = tracking.y2 - tracking.y1;
1019706f2543Smrg	rep.border_left   = border[0];
1020706f2543Smrg	rep.border_top    = border[1];
1021706f2543Smrg	rep.border_right  = border[2];
1022706f2543Smrg	rep.border_bottom = border[3];
1023706f2543Smrg    }
1024706f2543Smrg
1025706f2543Smrg    if (client->swapped) {
1026706f2543Smrg	swaps(&rep.sequenceNumber, n);
1027706f2543Smrg	swapl(&rep.length, n);
1028706f2543Smrg	swaps(&rep.timestamp, n);
1029706f2543Smrg	swaps(&rep.left, n);
1030706f2543Smrg	swaps(&rep.top, n);
1031706f2543Smrg	swaps(&rep.width, n);
1032706f2543Smrg	swaps(&rep.height, n);
1033706f2543Smrg	swaps(&rep.track_left, n);
1034706f2543Smrg	swaps(&rep.track_top, n);
1035706f2543Smrg	swaps(&rep.track_width, n);
1036706f2543Smrg	swaps(&rep.track_height, n);
1037706f2543Smrg	swaps(&rep.border_left, n);
1038706f2543Smrg	swaps(&rep.border_top, n);
1039706f2543Smrg	swaps(&rep.border_right, n);
1040706f2543Smrg	swaps(&rep.border_bottom, n);
1041706f2543Smrg    }
1042706f2543Smrg    WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
1043706f2543Smrg    return Success;
1044706f2543Smrg}
1045706f2543Smrg
1046706f2543Smrgint
1047706f2543SmrgProcRRSetPanning (ClientPtr client)
1048706f2543Smrg{
1049706f2543Smrg    REQUEST(xRRSetPanningReq);
1050706f2543Smrg    xRRSetPanningReply	rep;
1051706f2543Smrg    RRCrtcPtr		crtc;
1052706f2543Smrg    ScreenPtr		pScreen;
1053706f2543Smrg    rrScrPrivPtr	pScrPriv;
1054706f2543Smrg    TimeStamp		time;
1055706f2543Smrg    BoxRec		total;
1056706f2543Smrg    BoxRec		tracking;
1057706f2543Smrg    INT16		border[4];
1058706f2543Smrg    int			n;
1059706f2543Smrg
1060706f2543Smrg    REQUEST_SIZE_MATCH(xRRSetPanningReq);
1061706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1062706f2543Smrg
1063706f2543Smrg    /* All crtcs must be associated with screens before client
1064706f2543Smrg     * requests are processed
1065706f2543Smrg     */
1066706f2543Smrg    pScreen = crtc->pScreen;
1067706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
1068706f2543Smrg
1069706f2543Smrg    if (!pScrPriv) {
1070706f2543Smrg	time = currentTime;
1071706f2543Smrg	rep.status = RRSetConfigFailed;
1072706f2543Smrg	goto sendReply;
1073706f2543Smrg    }
1074706f2543Smrg
1075706f2543Smrg    time = ClientTimeToServerTime(stuff->timestamp);
1076706f2543Smrg
1077706f2543Smrg    if (!pScrPriv->rrGetPanning)
1078706f2543Smrg	return RRErrorBase + BadRRCrtc;
1079706f2543Smrg
1080706f2543Smrg    total.x1    = stuff->left;
1081706f2543Smrg    total.y1    = stuff->top;
1082706f2543Smrg    total.x2    = total.x1 + stuff->width;
1083706f2543Smrg    total.y2    = total.y1 + stuff->height;
1084706f2543Smrg    tracking.x1 = stuff->track_left;
1085706f2543Smrg    tracking.y1 = stuff->track_top;
1086706f2543Smrg    tracking.x2 = tracking.x1 + stuff->track_width;
1087706f2543Smrg    tracking.y2 = tracking.y1 + stuff->track_height;
1088706f2543Smrg    border[0]   = stuff->border_left;
1089706f2543Smrg    border[1]   = stuff->border_top;
1090706f2543Smrg    border[2]   = stuff->border_right;
1091706f2543Smrg    border[3]   = stuff->border_bottom;
1092706f2543Smrg
1093706f2543Smrg    if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
1094706f2543Smrg	return BadMatch;
1095706f2543Smrg
1096706f2543Smrg    pScrPriv->lastSetTime = time;
1097706f2543Smrg
1098706f2543Smrg    rep.status = RRSetConfigSuccess;
1099706f2543Smrg
1100706f2543SmrgsendReply:
1101706f2543Smrg    rep.type = X_Reply;
1102706f2543Smrg    rep.sequenceNumber = client->sequence;
1103706f2543Smrg    rep.length = 0;
1104706f2543Smrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
1105706f2543Smrg
1106706f2543Smrg    if (client->swapped) {
1107706f2543Smrg	swaps(&rep.sequenceNumber, n);
1108706f2543Smrg	swapl(&rep.length, n);
1109706f2543Smrg	swaps(&rep.newTimestamp, n);
1110706f2543Smrg    }
1111706f2543Smrg    WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
1112706f2543Smrg    return Success;
1113706f2543Smrg}
1114706f2543Smrg
1115706f2543Smrgint
1116706f2543SmrgProcRRGetCrtcGammaSize (ClientPtr client)
1117706f2543Smrg{
1118706f2543Smrg    REQUEST(xRRGetCrtcGammaSizeReq);
1119706f2543Smrg    xRRGetCrtcGammaSizeReply	reply;
1120706f2543Smrg    RRCrtcPtr			crtc;
1121706f2543Smrg    int				n;
1122706f2543Smrg
1123706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1124706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1125706f2543Smrg
1126706f2543Smrg    /* Gamma retrieval failed, any better error? */
1127706f2543Smrg    if (!RRCrtcGammaGet(crtc))
1128706f2543Smrg        return RRErrorBase + BadRRCrtc;
1129706f2543Smrg
1130706f2543Smrg    reply.type = X_Reply;
1131706f2543Smrg    reply.sequenceNumber = client->sequence;
1132706f2543Smrg    reply.length = 0;
1133706f2543Smrg    reply.size = crtc->gammaSize;
1134706f2543Smrg    if (client->swapped) {
1135706f2543Smrg	swaps (&reply.sequenceNumber, n);
1136706f2543Smrg	swapl (&reply.length, n);
1137706f2543Smrg	swaps (&reply.size, n);
1138706f2543Smrg    }
1139706f2543Smrg    WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
1140706f2543Smrg    return Success;
1141706f2543Smrg}
1142706f2543Smrg
1143706f2543Smrgint
1144706f2543SmrgProcRRGetCrtcGamma (ClientPtr client)
1145706f2543Smrg{
1146706f2543Smrg    REQUEST(xRRGetCrtcGammaReq);
1147706f2543Smrg    xRRGetCrtcGammaReply	reply;
1148706f2543Smrg    RRCrtcPtr			crtc;
1149706f2543Smrg    int				n;
1150706f2543Smrg    unsigned long		len;
1151706f2543Smrg    char			*extra = NULL;
1152706f2543Smrg
1153706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1154706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1155706f2543Smrg
1156706f2543Smrg    /* Gamma retrieval failed, any better error? */
1157706f2543Smrg    if (!RRCrtcGammaGet(crtc))
1158706f2543Smrg        return RRErrorBase + BadRRCrtc;
1159706f2543Smrg
1160706f2543Smrg    len = crtc->gammaSize * 3 * 2;
1161706f2543Smrg
1162706f2543Smrg    if (crtc->gammaSize) {
1163706f2543Smrg	extra = malloc(len);
1164706f2543Smrg	if (!extra)
1165706f2543Smrg	    return BadAlloc;
1166706f2543Smrg    }
1167706f2543Smrg
1168706f2543Smrg    reply.type = X_Reply;
1169706f2543Smrg    reply.sequenceNumber = client->sequence;
1170706f2543Smrg    reply.length = bytes_to_int32(len);
1171706f2543Smrg    reply.size = crtc->gammaSize;
1172706f2543Smrg    if (client->swapped) {
1173706f2543Smrg	swaps (&reply.sequenceNumber, n);
1174706f2543Smrg	swapl (&reply.length, n);
1175706f2543Smrg	swaps (&reply.size, n);
1176706f2543Smrg    }
1177706f2543Smrg    WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
1178706f2543Smrg    if (crtc->gammaSize)
1179706f2543Smrg    {
1180706f2543Smrg	memcpy(extra, crtc->gammaRed, len);
1181706f2543Smrg	client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
1182706f2543Smrg	WriteSwappedDataToClient (client, len, extra);
1183706f2543Smrg	free(extra);
1184706f2543Smrg    }
1185706f2543Smrg    return Success;
1186706f2543Smrg}
1187706f2543Smrg
1188706f2543Smrgint
1189706f2543SmrgProcRRSetCrtcGamma (ClientPtr client)
1190706f2543Smrg{
1191706f2543Smrg    REQUEST(xRRSetCrtcGammaReq);
1192706f2543Smrg    RRCrtcPtr			crtc;
1193706f2543Smrg    unsigned long		len;
1194706f2543Smrg    CARD16			*red, *green, *blue;
1195706f2543Smrg
1196706f2543Smrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1197706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1198706f2543Smrg
1199706f2543Smrg    len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
1200706f2543Smrg    if (len < (stuff->size * 3 + 1) >> 1)
1201706f2543Smrg	return BadLength;
1202706f2543Smrg
1203706f2543Smrg    if (stuff->size != crtc->gammaSize)
1204706f2543Smrg	return BadMatch;
1205706f2543Smrg
1206706f2543Smrg    red = (CARD16 *) (stuff + 1);
1207706f2543Smrg    green = red + crtc->gammaSize;
1208706f2543Smrg    blue = green + crtc->gammaSize;
1209706f2543Smrg
1210706f2543Smrg    RRCrtcGammaSet (crtc, red, green, blue);
1211706f2543Smrg
1212706f2543Smrg    return Success;
1213706f2543Smrg}
1214706f2543Smrg
1215706f2543Smrg/* Version 1.3 additions */
1216706f2543Smrg
1217706f2543Smrgint
1218706f2543SmrgProcRRSetCrtcTransform (ClientPtr client)
1219706f2543Smrg{
1220706f2543Smrg    REQUEST(xRRSetCrtcTransformReq);
1221706f2543Smrg    RRCrtcPtr		    crtc;
1222706f2543Smrg    PictTransform	    transform;
1223706f2543Smrg    struct pixman_f_transform f_transform, f_inverse;
1224706f2543Smrg    char		    *filter;
1225706f2543Smrg    int			    nbytes;
1226706f2543Smrg    xFixed		    *params;
1227706f2543Smrg    int			    nparams;
1228706f2543Smrg
1229706f2543Smrg    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1230706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1231706f2543Smrg
1232706f2543Smrg    PictTransform_from_xRenderTransform (&transform, &stuff->transform);
1233706f2543Smrg    pixman_f_transform_from_pixman_transform (&f_transform, &transform);
1234706f2543Smrg    if (!pixman_f_transform_invert (&f_inverse, &f_transform))
1235706f2543Smrg	return BadMatch;
1236706f2543Smrg
1237706f2543Smrg    filter = (char *) (stuff + 1);
1238706f2543Smrg    nbytes = stuff->nbytesFilter;
1239706f2543Smrg    params = (xFixed *) (filter + pad_to_int32(nbytes));
1240706f2543Smrg    nparams = ((xFixed *) stuff + client->req_len) - params;
1241706f2543Smrg    if (nparams < 0)
1242706f2543Smrg	return BadLength;
1243706f2543Smrg
1244706f2543Smrg    return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
1245706f2543Smrg			       filter, nbytes, params, nparams);
1246706f2543Smrg}
1247706f2543Smrg
1248706f2543Smrg
1249706f2543Smrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1250706f2543Smrg
1251706f2543Smrgstatic int
1252706f2543Smrgtransform_filter_length (RRTransformPtr transform)
1253706f2543Smrg{
1254706f2543Smrg    int	nbytes, nparams;
1255706f2543Smrg
1256706f2543Smrg    if (transform->filter == NULL)
1257706f2543Smrg	return 0;
1258706f2543Smrg    nbytes = strlen (transform->filter->name);
1259706f2543Smrg    nparams = transform->nparams;
1260706f2543Smrg    return pad_to_int32(nbytes) + (nparams * sizeof (xFixed));
1261706f2543Smrg}
1262706f2543Smrg
1263706f2543Smrgstatic int
1264706f2543Smrgtransform_filter_encode (ClientPtr client, char *output,
1265706f2543Smrg			 CARD16	*nbytesFilter,
1266706f2543Smrg			 CARD16	*nparamsFilter,
1267706f2543Smrg			 RRTransformPtr transform)
1268706f2543Smrg{
1269706f2543Smrg    int	    nbytes, nparams;
1270706f2543Smrg    int	    n;
1271706f2543Smrg
1272706f2543Smrg    if (transform->filter == NULL) {
1273706f2543Smrg	*nbytesFilter = 0;
1274706f2543Smrg	*nparamsFilter = 0;
1275706f2543Smrg	return 0;
1276706f2543Smrg    }
1277706f2543Smrg    nbytes = strlen (transform->filter->name);
1278706f2543Smrg    nparams = transform->nparams;
1279706f2543Smrg    *nbytesFilter = nbytes;
1280706f2543Smrg    *nparamsFilter = nparams;
1281706f2543Smrg    memcpy (output, transform->filter->name, nbytes);
1282706f2543Smrg    while ((nbytes & 3) != 0)
1283706f2543Smrg	output[nbytes++] = 0;
1284706f2543Smrg    memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
1285706f2543Smrg    if (client->swapped) {
1286706f2543Smrg	swaps (nbytesFilter, n);
1287706f2543Smrg	swaps (nparamsFilter, n);
1288706f2543Smrg	SwapLongs ((CARD32 *) (output + nbytes), nparams);
1289706f2543Smrg    }
1290706f2543Smrg    nbytes += nparams * sizeof (xFixed);
1291706f2543Smrg    return nbytes;
1292706f2543Smrg}
1293706f2543Smrg
1294706f2543Smrgstatic void
1295706f2543Smrgtransform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
1296706f2543Smrg{
1297706f2543Smrg    xRenderTransform_from_PictTransform (wire, pict);
1298706f2543Smrg    if (client->swapped)
1299706f2543Smrg	SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1300706f2543Smrg}
1301706f2543Smrg
1302706f2543Smrgint
1303706f2543SmrgProcRRGetCrtcTransform (ClientPtr client)
1304706f2543Smrg{
1305706f2543Smrg    REQUEST(xRRGetCrtcTransformReq);
1306706f2543Smrg    xRRGetCrtcTransformReply	*reply;
1307706f2543Smrg    RRCrtcPtr			crtc;
1308706f2543Smrg    int				n, nextra;
1309706f2543Smrg    RRTransformPtr		current, pending;
1310706f2543Smrg    char			*extra;
1311706f2543Smrg
1312706f2543Smrg    REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
1313706f2543Smrg    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1314706f2543Smrg
1315706f2543Smrg    pending = &crtc->client_pending_transform;
1316706f2543Smrg    current = &crtc->client_current_transform;
1317706f2543Smrg
1318706f2543Smrg    nextra = (transform_filter_length (pending) +
1319706f2543Smrg	      transform_filter_length (current));
1320706f2543Smrg
1321706f2543Smrg    reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra);
1322706f2543Smrg    if (!reply)
1323706f2543Smrg	return BadAlloc;
1324706f2543Smrg
1325706f2543Smrg    extra = (char *) (reply + 1);
1326706f2543Smrg    reply->type = X_Reply;
1327706f2543Smrg    reply->sequenceNumber = client->sequence;
1328706f2543Smrg    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1329706f2543Smrg
1330706f2543Smrg    reply->hasTransforms = crtc->transforms;
1331706f2543Smrg
1332706f2543Smrg    transform_encode (client, &reply->pendingTransform, &pending->transform);
1333706f2543Smrg    extra += transform_filter_encode (client, extra,
1334706f2543Smrg				      &reply->pendingNbytesFilter,
1335706f2543Smrg				      &reply->pendingNparamsFilter,
1336706f2543Smrg				      pending);
1337706f2543Smrg
1338706f2543Smrg    transform_encode (client, &reply->currentTransform, &current->transform);
1339706f2543Smrg    extra += transform_filter_encode (client, extra,
1340706f2543Smrg				      &reply->currentNbytesFilter,
1341706f2543Smrg				      &reply->currentNparamsFilter,
1342706f2543Smrg				      current);
1343706f2543Smrg
1344706f2543Smrg    if (client->swapped) {
1345706f2543Smrg	swaps (&reply->sequenceNumber, n);
1346706f2543Smrg	swapl (&reply->length, n);
1347706f2543Smrg    }
1348706f2543Smrg    WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
1349706f2543Smrg    free(reply);
1350706f2543Smrg    return Success;
1351706f2543Smrg}
1352