rrcrtc.c revision 4642e01f
1/*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "swaprep.h"
25#include "registry.h"
26
27RESTYPE	RRCrtcType;
28
29/*
30 * Notify the CRTC of some change
31 */
32void
33RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
34{
35    ScreenPtr	pScreen = crtc->pScreen;
36
37    crtc->changed = TRUE;
38    if (pScreen)
39    {
40	rrScrPriv(pScreen);
41
42	pScrPriv->changed = TRUE;
43	/*
44	 * Send ConfigureNotify on any layout change
45	 */
46	if (layoutChanged)
47	    pScrPriv->layoutChanged = TRUE;
48    }
49}
50
51/*
52 * Create a CRTC
53 */
54RRCrtcPtr
55RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
56{
57    RRCrtcPtr	    crtc;
58    RRCrtcPtr	    *crtcs;
59    rrScrPrivPtr    pScrPriv;
60
61    if (!RRInit())
62	return NULL;
63
64    pScrPriv = rrGetScrPriv(pScreen);
65
66    /* make space for the crtc pointer */
67    if (pScrPriv->numCrtcs)
68	crtcs = xrealloc (pScrPriv->crtcs,
69			  (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
70    else
71	crtcs = xalloc (sizeof (RRCrtcPtr));
72    if (!crtcs)
73	return FALSE;
74    pScrPriv->crtcs = crtcs;
75
76    crtc = xcalloc (1, sizeof (RRCrtcRec));
77    if (!crtc)
78	return NULL;
79    crtc->id = FakeClientID (0);
80    crtc->pScreen = pScreen;
81    crtc->mode = NULL;
82    crtc->x = 0;
83    crtc->y = 0;
84    crtc->rotation = RR_Rotate_0;
85    crtc->rotations = RR_Rotate_0;
86    crtc->outputs = NULL;
87    crtc->numOutputs = 0;
88    crtc->gammaSize = 0;
89    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
90    crtc->changed = FALSE;
91    crtc->devPrivate = devPrivate;
92    RRTransformInit (&crtc->client_pending_transform);
93    RRTransformInit (&crtc->client_current_transform);
94    pixman_transform_init_identity (&crtc->transform);
95    pixman_f_transform_init_identity (&crtc->f_transform);
96    pixman_f_transform_init_identity (&crtc->f_inverse);
97
98    if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
99	return NULL;
100
101    /* attach the screen and crtc together */
102    crtc->pScreen = pScreen;
103    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
104
105    return crtc;
106}
107
108/*
109 * Set the allowed rotations on a CRTC
110 */
111void
112RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
113{
114    crtc->rotations = rotations;
115}
116
117/*
118 * Set whether transforms are allowed on a CRTC
119 */
120void
121RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
122{
123    crtc->transforms = transforms;
124}
125
126/*
127 * Notify the extension that the Crtc has been reconfigured,
128 * the driver calls this whenever it has updated the mode
129 */
130Bool
131RRCrtcNotify (RRCrtcPtr	    crtc,
132	      RRModePtr	    mode,
133	      int	    x,
134	      int	    y,
135	      Rotation	    rotation,
136	      RRTransformPtr transform,
137	      int	    numOutputs,
138	      RROutputPtr   *outputs)
139{
140    int	    i, j;
141
142    /*
143     * Check to see if any of the new outputs were
144     * not in the old list and mark them as changed
145     */
146    for (i = 0; i < numOutputs; i++)
147    {
148	for (j = 0; j < crtc->numOutputs; j++)
149	    if (outputs[i] == crtc->outputs[j])
150		break;
151	if (j == crtc->numOutputs)
152	{
153	    outputs[i]->crtc = crtc;
154	    RROutputChanged (outputs[i], FALSE);
155	    RRCrtcChanged (crtc, FALSE);
156	}
157    }
158    /*
159     * Check to see if any of the old outputs are
160     * not in the new list and mark them as changed
161     */
162    for (j = 0; j < crtc->numOutputs; j++)
163    {
164	for (i = 0; i < numOutputs; i++)
165	    if (outputs[i] == crtc->outputs[j])
166		break;
167	if (i == numOutputs)
168	{
169	    if (crtc->outputs[j]->crtc == crtc)
170		crtc->outputs[j]->crtc = NULL;
171	    RROutputChanged (crtc->outputs[j], FALSE);
172	    RRCrtcChanged (crtc, FALSE);
173	}
174    }
175    /*
176     * Reallocate the crtc output array if necessary
177     */
178    if (numOutputs != crtc->numOutputs)
179    {
180	RROutputPtr *newoutputs;
181
182	if (numOutputs)
183	{
184	    if (crtc->numOutputs)
185		newoutputs = xrealloc (crtc->outputs,
186				    numOutputs * sizeof (RROutputPtr));
187	    else
188		newoutputs = xalloc (numOutputs * sizeof (RROutputPtr));
189	    if (!newoutputs)
190		return FALSE;
191	}
192	else
193	{
194	    if (crtc->outputs)
195		xfree (crtc->outputs);
196	    newoutputs = NULL;
197	}
198	crtc->outputs = newoutputs;
199	crtc->numOutputs = numOutputs;
200    }
201    /*
202     * Copy the new list of outputs into the crtc
203     */
204    memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
205    /*
206     * Update remaining crtc fields
207     */
208    if (mode != crtc->mode)
209    {
210	if (crtc->mode)
211	    RRModeDestroy (crtc->mode);
212	crtc->mode = mode;
213	if (mode != NULL)
214	    mode->refcnt++;
215	RRCrtcChanged (crtc, TRUE);
216    }
217    if (x != crtc->x)
218    {
219	crtc->x = x;
220	RRCrtcChanged (crtc, TRUE);
221    }
222    if (y != crtc->y)
223    {
224	crtc->y = y;
225	RRCrtcChanged (crtc, TRUE);
226    }
227    if (rotation != crtc->rotation)
228    {
229	crtc->rotation = rotation;
230	RRCrtcChanged (crtc, TRUE);
231    }
232    if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
233	RRTransformCopy (&crtc->client_current_transform, transform);
234	RRCrtcChanged (crtc, TRUE);
235    }
236    if (crtc->changed && mode)
237    {
238	RRTransformCompute (x, y,
239			    mode->mode.width, mode->mode.height,
240			    rotation,
241			    &crtc->client_current_transform,
242			    &crtc->transform, &crtc->f_transform,
243			    &crtc->f_inverse);
244    }
245    return TRUE;
246}
247
248void
249RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
250{
251    ScreenPtr pScreen = pWin->drawable.pScreen;
252    rrScrPriv (pScreen);
253    xRRCrtcChangeNotifyEvent	ce;
254    RRModePtr	mode = crtc->mode;
255
256    ce.type = RRNotify + RREventBase;
257    ce.subCode = RRNotify_CrtcChange;
258    ce.sequenceNumber = client->sequence;
259    ce.timestamp = pScrPriv->lastSetTime.milliseconds;
260    ce.window = pWin->drawable.id;
261    ce.crtc = crtc->id;
262    ce.rotation = crtc->rotation;
263    if (mode)
264    {
265	ce.mode = mode->mode.id;
266	ce.x = crtc->x;
267	ce.y = crtc->y;
268	ce.width = mode->mode.width;
269	ce.height = mode->mode.height;
270    }
271    else
272    {
273	ce.mode = None;
274	ce.x = 0;
275	ce.y = 0;
276	ce.width = 0;
277	ce.height = 0;
278    }
279    WriteEventsToClient (client, 1, (xEvent *) &ce);
280}
281
282static Bool
283RRCrtcPendingProperties (RRCrtcPtr crtc)
284{
285    ScreenPtr	pScreen = crtc->pScreen;
286    rrScrPriv(pScreen);
287    int		o;
288
289    for (o = 0; o < pScrPriv->numOutputs; o++)
290    {
291	RROutputPtr output = pScrPriv->outputs[o];
292	if (output->crtc == crtc && output->pendingProperties)
293	    return TRUE;
294    }
295    return FALSE;
296}
297
298/*
299 * Request that the Crtc be reconfigured
300 */
301Bool
302RRCrtcSet (RRCrtcPtr    crtc,
303	   RRModePtr	mode,
304	   int		x,
305	   int		y,
306	   Rotation	rotation,
307	   int		numOutputs,
308	   RROutputPtr  *outputs)
309{
310    ScreenPtr	pScreen = crtc->pScreen;
311    Bool	ret = FALSE;
312    rrScrPriv(pScreen);
313
314    /* See if nothing changed */
315    if (crtc->mode == mode &&
316	crtc->x == x &&
317	crtc->y == y &&
318	crtc->rotation == rotation &&
319	crtc->numOutputs == numOutputs &&
320	!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
321	!RRCrtcPendingProperties (crtc) &&
322	!RRCrtcPendingTransform (crtc))
323    {
324	ret = TRUE;
325    }
326    else
327    {
328#if RANDR_12_INTERFACE
329	if (pScrPriv->rrCrtcSet)
330	{
331	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
332					  rotation, numOutputs, outputs);
333	}
334	else
335#endif
336	{
337#if RANDR_10_INTERFACE
338	    if (pScrPriv->rrSetConfig)
339	    {
340		RRScreenSize	    size;
341		RRScreenRate	    rate;
342
343		if (!mode)
344		{
345		    RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
346		    ret = TRUE;
347		}
348		else
349		{
350		    size.width = mode->mode.width;
351		    size.height = mode->mode.height;
352		    if (outputs[0]->mmWidth && outputs[0]->mmHeight)
353		    {
354			size.mmWidth = outputs[0]->mmWidth;
355			size.mmHeight = outputs[0]->mmHeight;
356		    }
357		    else
358		    {
359			size.mmWidth = pScreen->mmWidth;
360			size.mmHeight = pScreen->mmHeight;
361		    }
362		    size.nRates = 1;
363		    rate.rate = RRVerticalRefresh (&mode->mode);
364		    size.pRates = &rate;
365		    ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
366		    /*
367		     * Old 1.0 interface tied screen size to mode size
368		     */
369		    if (ret)
370		    {
371			RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
372			RRScreenSizeNotify (pScreen);
373		    }
374		}
375	    }
376#endif
377	}
378	if (ret)
379	{
380	    int	o;
381	    RRTellChanged (pScreen);
382
383	    for (o = 0; o < numOutputs; o++)
384		RRPostPendingProperties (outputs[o]);
385	}
386    }
387    return ret;
388}
389
390/*
391 * Return crtc transform
392 */
393RRTransformPtr
394RRCrtcGetTransform (RRCrtcPtr crtc)
395{
396    RRTransformPtr  transform = &crtc->client_pending_transform;
397
398    if (pixman_transform_is_identity (&transform->transform))
399	return NULL;
400    return transform;
401}
402
403/*
404 * Check whether the pending and current transforms are the same
405 */
406Bool
407RRCrtcPendingTransform (RRCrtcPtr crtc)
408{
409    return memcmp (&crtc->client_current_transform.transform,
410		   &crtc->client_pending_transform.transform,
411		   sizeof (PictTransform)) != 0;
412}
413
414/*
415 * Destroy a Crtc at shutdown
416 */
417void
418RRCrtcDestroy (RRCrtcPtr crtc)
419{
420    FreeResource (crtc->id, 0);
421}
422
423static int
424RRCrtcDestroyResource (pointer value, XID pid)
425{
426    RRCrtcPtr	crtc = (RRCrtcPtr) value;
427    ScreenPtr	pScreen = crtc->pScreen;
428
429    if (pScreen)
430    {
431	rrScrPriv(pScreen);
432	int		i;
433
434	for (i = 0; i < pScrPriv->numCrtcs; i++)
435	{
436	    if (pScrPriv->crtcs[i] == crtc)
437	    {
438		memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
439			 (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
440		--pScrPriv->numCrtcs;
441		break;
442	    }
443	}
444    }
445    if (crtc->gammaRed)
446	xfree (crtc->gammaRed);
447    if (crtc->mode)
448	RRModeDestroy (crtc->mode);
449    xfree (crtc);
450    return 1;
451}
452
453/*
454 * Request that the Crtc gamma be changed
455 */
456
457Bool
458RRCrtcGammaSet (RRCrtcPtr   crtc,
459		CARD16	    *red,
460		CARD16	    *green,
461		CARD16	    *blue)
462{
463    Bool	ret = TRUE;
464#if RANDR_12_INTERFACE
465    ScreenPtr	pScreen = crtc->pScreen;
466#endif
467
468    memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
469    memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
470    memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
471#if RANDR_12_INTERFACE
472    if (pScreen)
473    {
474	rrScrPriv(pScreen);
475	if (pScrPriv->rrCrtcSetGamma)
476	    ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
477    }
478#endif
479    return ret;
480}
481
482/*
483 * Notify the extension that the Crtc gamma has been changed
484 * The driver calls this whenever it has changed the gamma values
485 * in the RRCrtcRec
486 */
487
488Bool
489RRCrtcGammaNotify (RRCrtcPtr	crtc)
490{
491    return TRUE;    /* not much going on here */
492}
493
494static void
495RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
496		      int *width, int *height)
497{
498    BoxRec  box;
499
500    if (mode == NULL) {
501	*width = 0;
502	*height = 0;
503	return;
504    }
505
506    box.x1 = 0;
507    box.y1 = 0;
508    box.x2 = mode->mode.width;
509    box.y2 = mode->mode.height;
510
511    pixman_transform_bounds (transform, &box);
512    *width = box.x2 - box.x1;
513    *height = box.y2 - box.y1;
514}
515
516/**
517 * Returns the width/height that the crtc scans out from the framebuffer
518 */
519void
520RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
521{
522    return RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
523}
524
525/*
526 * Set the size of the gamma table at server startup time
527 */
528
529Bool
530RRCrtcGammaSetSize (RRCrtcPtr	crtc,
531		    int		size)
532{
533    CARD16  *gamma;
534
535    if (size == crtc->gammaSize)
536	return TRUE;
537    if (size)
538    {
539	gamma = xalloc (size * 3 * sizeof (CARD16));
540	if (!gamma)
541	    return FALSE;
542    }
543    else
544	gamma = NULL;
545    if (crtc->gammaRed)
546	xfree (crtc->gammaRed);
547    crtc->gammaRed = gamma;
548    crtc->gammaGreen = gamma + size;
549    crtc->gammaBlue = gamma + size*2;
550    crtc->gammaSize = size;
551    return TRUE;
552}
553
554/*
555 * Set the pending CRTC transformation
556 */
557
558int
559RRCrtcTransformSet (RRCrtcPtr		crtc,
560		    PictTransformPtr	transform,
561		    struct pixman_f_transform *f_transform,
562		    struct pixman_f_transform *f_inverse,
563		    char		*filter_name,
564		    int			filter_len,
565		    xFixed		*params,
566		    int			nparams)
567{
568    PictFilterPtr   filter = NULL;
569    int		    width = 0, height = 0;
570
571    if (!crtc->transforms)
572	return BadValue;
573
574    if (filter_len)
575    {
576	filter = PictureFindFilter (crtc->pScreen,
577				    filter_name,
578				    filter_len);
579	if (!filter)
580	    return BadName;
581	if (filter->ValidateParams)
582	{
583	    if (!filter->ValidateParams (crtc->pScreen, filter->id,
584					 params, nparams, &width, &height))
585		return BadMatch;
586	}
587	else {
588	    width = filter->width;
589	    height = filter->height;
590	}
591    }
592    else
593    {
594	if (nparams)
595	    return BadMatch;
596    }
597    if (!RRTransformSetFilter (&crtc->client_pending_transform,
598			       filter, params, nparams, width, height))
599	return BadAlloc;
600
601    crtc->client_pending_transform.transform = *transform;
602    crtc->client_pending_transform.f_transform = *f_transform;
603    crtc->client_pending_transform.f_inverse = *f_inverse;
604    return Success;
605}
606
607/*
608 * Initialize crtc type
609 */
610Bool
611RRCrtcInit (void)
612{
613    RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource);
614    if (!RRCrtcType)
615	return FALSE;
616    RegisterResourceName (RRCrtcType, "CRTC");
617    return TRUE;
618}
619
620int
621ProcRRGetCrtcInfo (ClientPtr client)
622{
623    REQUEST(xRRGetCrtcInfoReq);
624    xRRGetCrtcInfoReply	rep;
625    RRCrtcPtr			crtc;
626    CARD8			*extra;
627    unsigned long		extraLen;
628    ScreenPtr			pScreen;
629    rrScrPrivPtr		pScrPriv;
630    RRModePtr			mode;
631    RROutput			*outputs;
632    RROutput			*possible;
633    int				i, j, k, n;
634    int				width, height;
635    BoxRec			panned_area;
636
637    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
638    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
639
640    if (!crtc)
641	return RRErrorBase + BadRRCrtc;
642
643    /* All crtcs must be associated with screens before client
644     * requests are processed
645     */
646    pScreen = crtc->pScreen;
647    pScrPriv = rrGetScrPriv(pScreen);
648
649    mode = crtc->mode;
650
651    rep.type = X_Reply;
652    rep.status = RRSetConfigSuccess;
653    rep.sequenceNumber = client->sequence;
654    rep.length = 0;
655    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
656    if (pScrPriv->rrGetPanning &&
657	pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
658	(panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
659    {
660 	rep.x = panned_area.x1;
661	rep.y = panned_area.y1;
662	rep.width = panned_area.x2 - panned_area.x1;
663	rep.height = panned_area.y2 - panned_area.y1;
664    }
665    else
666    {
667	RRCrtcGetScanoutSize (crtc, &width, &height);
668	rep.x = crtc->x;
669	rep.y = crtc->y;
670	rep.width = width;
671	rep.height = height;
672    }
673    rep.mode = mode ? mode->mode.id : 0;
674    rep.rotation = crtc->rotation;
675    rep.rotations = crtc->rotations;
676    rep.nOutput = crtc->numOutputs;
677    k = 0;
678    for (i = 0; i < pScrPriv->numOutputs; i++)
679	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
680	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
681		k++;
682    rep.nPossibleOutput = k;
683
684    rep.length = rep.nOutput + rep.nPossibleOutput;
685
686    extraLen = rep.length << 2;
687    if (extraLen)
688    {
689	extra = xalloc (extraLen);
690	if (!extra)
691	    return BadAlloc;
692    }
693    else
694	extra = NULL;
695
696    outputs = (RROutput *) extra;
697    possible = (RROutput *) (outputs + rep.nOutput);
698
699    for (i = 0; i < crtc->numOutputs; i++)
700    {
701	outputs[i] = crtc->outputs[i]->id;
702	if (client->swapped)
703	    swapl (&outputs[i], n);
704    }
705    k = 0;
706    for (i = 0; i < pScrPriv->numOutputs; i++)
707	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
708	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
709	    {
710		possible[k] = pScrPriv->outputs[i]->id;
711		if (client->swapped)
712		    swapl (&possible[k], n);
713		k++;
714	    }
715
716    if (client->swapped) {
717	swaps(&rep.sequenceNumber, n);
718	swapl(&rep.length, n);
719	swapl(&rep.timestamp, n);
720	swaps(&rep.x, n);
721	swaps(&rep.y, n);
722	swaps(&rep.width, n);
723	swaps(&rep.height, n);
724	swapl(&rep.mode, n);
725	swaps(&rep.rotation, n);
726	swaps(&rep.rotations, n);
727	swaps(&rep.nOutput, n);
728	swaps(&rep.nPossibleOutput, n);
729    }
730    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
731    if (extraLen)
732    {
733	WriteToClient (client, extraLen, (char *) extra);
734	xfree (extra);
735    }
736
737    return client->noClientException;
738}
739
740int
741ProcRRSetCrtcConfig (ClientPtr client)
742{
743    REQUEST(xRRSetCrtcConfigReq);
744    xRRSetCrtcConfigReply   rep;
745    ScreenPtr		    pScreen;
746    rrScrPrivPtr	    pScrPriv;
747    RRCrtcPtr		    crtc;
748    RRModePtr		    mode;
749    int			    numOutputs;
750    RROutputPtr		    *outputs = NULL;
751    RROutput		    *outputIds;
752    TimeStamp		    configTime;
753    TimeStamp		    time;
754    Rotation		    rotation;
755    int			    i, j;
756
757    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
758    numOutputs = (stuff->length - (SIZEOF (xRRSetCrtcConfigReq) >> 2));
759
760    crtc = LookupIDByType (stuff->crtc, RRCrtcType);
761    if (!crtc)
762    {
763	client->errorValue = stuff->crtc;
764	return RRErrorBase + BadRRCrtc;
765    }
766    if (stuff->mode == None)
767    {
768	mode = NULL;
769	if (numOutputs > 0)
770	    return BadMatch;
771    }
772    else
773    {
774	mode = LookupIDByType (stuff->mode, RRModeType);
775	if (!mode)
776	{
777	    client->errorValue = stuff->mode;
778	    return RRErrorBase + BadRRMode;
779	}
780	if (numOutputs == 0)
781	    return BadMatch;
782    }
783    if (numOutputs)
784    {
785	outputs = xalloc (numOutputs * sizeof (RROutputPtr));
786	if (!outputs)
787	    return BadAlloc;
788    }
789    else
790	outputs = NULL;
791
792    outputIds = (RROutput *) (stuff + 1);
793    for (i = 0; i < numOutputs; i++)
794    {
795	outputs[i] = (RROutputPtr) LookupIDByType (outputIds[i], RROutputType);
796	if (!outputs[i])
797	{
798	    client->errorValue = outputIds[i];
799	    if (outputs)
800		xfree (outputs);
801	    return RRErrorBase + BadRROutput;
802	}
803	/* validate crtc for this output */
804	for (j = 0; j < outputs[i]->numCrtcs; j++)
805	    if (outputs[i]->crtcs[j] == crtc)
806		break;
807	if (j == outputs[i]->numCrtcs)
808	{
809	    if (outputs)
810		xfree (outputs);
811	    return BadMatch;
812	}
813	/* validate mode for this output */
814	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
815	{
816	    RRModePtr	m = (j < outputs[i]->numModes ?
817			     outputs[i]->modes[j] :
818			     outputs[i]->userModes[j - outputs[i]->numModes]);
819	    if (m == mode)
820		break;
821	}
822	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
823	{
824	    if (outputs)
825		xfree (outputs);
826	    return BadMatch;
827	}
828    }
829    /* validate clones */
830    for (i = 0; i < numOutputs; i++)
831    {
832	for (j = 0; j < numOutputs; j++)
833	{
834	    int k;
835	    if (i == j)
836		continue;
837	    for (k = 0; k < outputs[i]->numClones; k++)
838	    {
839		if (outputs[i]->clones[k] == outputs[j])
840		    break;
841	    }
842	    if (k == outputs[i]->numClones)
843	    {
844		if (outputs)
845		    xfree (outputs);
846		return BadMatch;
847	    }
848	}
849    }
850
851    pScreen = crtc->pScreen;
852    pScrPriv = rrGetScrPriv(pScreen);
853
854    time = ClientTimeToServerTime(stuff->timestamp);
855    configTime = ClientTimeToServerTime(stuff->configTimestamp);
856
857    if (!pScrPriv)
858    {
859	time = currentTime;
860	rep.status = RRSetConfigFailed;
861	goto sendReply;
862    }
863
864#if 0
865    /*
866     * if the client's config timestamp is not the same as the last config
867     * timestamp, then the config information isn't up-to-date and
868     * can't even be validated
869     */
870    if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0)
871    {
872	rep.status = RRSetConfigInvalidConfigTime;
873	goto sendReply;
874    }
875#endif
876
877    /*
878     * Validate requested rotation
879     */
880    rotation = (Rotation) stuff->rotation;
881
882    /* test the rotation bits only! */
883    switch (rotation & 0xf) {
884    case RR_Rotate_0:
885    case RR_Rotate_90:
886    case RR_Rotate_180:
887    case RR_Rotate_270:
888	break;
889    default:
890	/*
891	 * Invalid rotation
892	 */
893	client->errorValue = stuff->rotation;
894	if (outputs)
895	    xfree (outputs);
896	return BadValue;
897    }
898
899    if (mode)
900    {
901	if ((~crtc->rotations) & rotation)
902	{
903	    /*
904	     * requested rotation or reflection not supported by screen
905	     */
906	    client->errorValue = stuff->rotation;
907	    if (outputs)
908		xfree (outputs);
909	    return BadMatch;
910	}
911
912#ifdef RANDR_12_INTERFACE
913	/*
914	 * Check screen size bounds if the DDX provides a 1.2 interface
915	 * for setting screen size. Else, assume the CrtcSet sets
916	 * the size along with the mode. If the driver supports transforms,
917	 * then it must allow crtcs to display a subset of the screen, so
918	 * only do this check for drivers without transform support.
919	 */
920	if (pScrPriv->rrScreenSetSize && !crtc->transforms)
921	{
922	    int source_width;
923	    int	source_height;
924	    PictTransform transform;
925	    struct pixman_f_transform f_transform, f_inverse;
926
927	    RRTransformCompute (stuff->x, stuff->y,
928				mode->mode.width, mode->mode.height,
929				rotation,
930				&crtc->client_pending_transform,
931				&transform, &f_transform, &f_inverse);
932
933	    RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
934	    if (stuff->x + source_width > pScreen->width)
935	    {
936		client->errorValue = stuff->x;
937		if (outputs)
938		    xfree (outputs);
939		return BadValue;
940	    }
941
942	    if (stuff->y + source_height > pScreen->height)
943	    {
944		client->errorValue = stuff->y;
945		if (outputs)
946		    xfree (outputs);
947		return BadValue;
948	    }
949	}
950#endif
951    }
952
953    /*
954     * Make sure the requested set-time is not older than
955     * the last set-time
956     */
957    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
958    {
959	rep.status = RRSetConfigInvalidTime;
960	goto sendReply;
961    }
962
963    if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
964		   rotation, numOutputs, outputs))
965    {
966	rep.status = RRSetConfigFailed;
967	goto sendReply;
968    }
969    rep.status = RRSetConfigSuccess;
970
971sendReply:
972    if (outputs)
973	xfree (outputs);
974
975    rep.type = X_Reply;
976    /* rep.status has already been filled in */
977    rep.length = 0;
978    rep.sequenceNumber = client->sequence;
979    rep.newTimestamp = pScrPriv->lastConfigTime.milliseconds;
980
981    if (client->swapped)
982    {
983	int n;
984    	swaps(&rep.sequenceNumber, n);
985    	swapl(&rep.length, n);
986	swapl(&rep.newTimestamp, n);
987    }
988    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
989
990    return client->noClientException;
991}
992
993int
994ProcRRGetPanning (ClientPtr client)
995{
996    REQUEST(xRRGetPanningReq);
997    xRRGetPanningReply	rep;
998    RRCrtcPtr		crtc;
999    ScreenPtr		pScreen;
1000    rrScrPrivPtr	pScrPriv;
1001    BoxRec		total;
1002    BoxRec		tracking;
1003    INT16		border[4];
1004    int			n;
1005
1006    REQUEST_SIZE_MATCH(xRRGetPanningReq);
1007    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
1008
1009    if (!crtc)
1010	return RRErrorBase + BadRRCrtc;
1011
1012    /* All crtcs must be associated with screens before client
1013     * requests are processed
1014     */
1015    pScreen = crtc->pScreen;
1016    pScrPriv = rrGetScrPriv(pScreen);
1017
1018    if (!pScrPriv)
1019	return RRErrorBase + BadRRCrtc;
1020
1021    memset(&rep, 0, sizeof(rep));
1022    rep.type = X_Reply;
1023    rep.status = RRSetConfigSuccess;
1024    rep.sequenceNumber = client->sequence;
1025    rep.length = 1;
1026    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
1027
1028    if (pScrPriv->rrGetPanning &&
1029	pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
1030	rep.left          = total.x1;
1031	rep.top           = total.y1;
1032	rep.width         = total.x2 - total.x1;
1033	rep.height        = total.y2 - total.y1;
1034	rep.track_left    = tracking.x1;
1035	rep.track_top     = tracking.y1;
1036	rep.track_width   = tracking.x2 - tracking.x1;
1037	rep.track_height  = tracking.y2 - tracking.y1;
1038	rep.border_left   = border[0];
1039	rep.border_top    = border[1];
1040	rep.border_right  = border[2];
1041	rep.border_bottom = border[3];
1042    }
1043
1044    if (client->swapped) {
1045	swaps(&rep.sequenceNumber, n);
1046	swapl(&rep.length, n);
1047	swaps(&rep.timestamp, n);
1048	swaps(&rep.left, n);
1049	swaps(&rep.top, n);
1050	swaps(&rep.width, n);
1051	swaps(&rep.height, n);
1052	swaps(&rep.track_left, n);
1053	swaps(&rep.track_top, n);
1054	swaps(&rep.track_width, n);
1055	swaps(&rep.track_height, n);
1056	swaps(&rep.border_left, n);
1057	swaps(&rep.border_top, n);
1058	swaps(&rep.border_right, n);
1059	swaps(&rep.border_bottom, n);
1060    }
1061    WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
1062    return client->noClientException;
1063}
1064
1065int
1066ProcRRSetPanning (ClientPtr client)
1067{
1068    REQUEST(xRRSetPanningReq);
1069    xRRSetPanningReply	rep;
1070    RRCrtcPtr		crtc;
1071    ScreenPtr		pScreen;
1072    rrScrPrivPtr	pScrPriv;
1073    TimeStamp		time;
1074    BoxRec		total;
1075    BoxRec		tracking;
1076    INT16		border[4];
1077    int			n;
1078
1079    REQUEST_SIZE_MATCH(xRRSetPanningReq);
1080    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
1081
1082    if (!crtc)
1083	return RRErrorBase + BadRRCrtc;
1084
1085
1086    /* All crtcs must be associated with screens before client
1087     * requests are processed
1088     */
1089    pScreen = crtc->pScreen;
1090    pScrPriv = rrGetScrPriv(pScreen);
1091
1092    if (!pScrPriv) {
1093	time = currentTime;
1094	rep.status = RRSetConfigFailed;
1095	goto sendReply;
1096    }
1097
1098    time = ClientTimeToServerTime(stuff->timestamp);
1099
1100    /*
1101     * Make sure the requested set-time is not older than
1102     * the last set-time
1103     */
1104    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
1105    {
1106	rep.status = RRSetConfigInvalidTime;
1107	goto sendReply;
1108    }
1109
1110    if (!pScrPriv->rrGetPanning)
1111	return RRErrorBase + BadRRCrtc;
1112
1113    total.x1    = stuff->left;
1114    total.y1    = stuff->top;
1115    total.x2    = total.x1 + stuff->width;
1116    total.y2    = total.y1 + stuff->height;
1117    tracking.x1 = stuff->track_left;
1118    tracking.y1 = stuff->track_top;
1119    tracking.x2 = tracking.x1 + stuff->track_width;
1120    tracking.y2 = tracking.y1 + stuff->track_height;
1121    border[0]   = stuff->border_left;
1122    border[1]   = stuff->border_top;
1123    border[2]   = stuff->border_right;
1124    border[3]   = stuff->border_bottom;
1125
1126    if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
1127	return BadMatch;
1128
1129    rep.status = RRSetConfigSuccess;
1130
1131sendReply:
1132    rep.type = X_Reply;
1133    rep.sequenceNumber = client->sequence;
1134    rep.length = 0;
1135    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
1136
1137    if (client->swapped) {
1138	swaps(&rep.sequenceNumber, n);
1139	swapl(&rep.length, n);
1140	swaps(&rep.newTimestamp, n);
1141    }
1142    WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
1143    return client->noClientException;
1144}
1145
1146int
1147ProcRRGetCrtcGammaSize (ClientPtr client)
1148{
1149    REQUEST(xRRGetCrtcGammaSizeReq);
1150    xRRGetCrtcGammaSizeReply	reply;
1151    RRCrtcPtr			crtc;
1152    int				n;
1153
1154    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1155    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
1156    if (!crtc)
1157	return RRErrorBase + BadRRCrtc;
1158
1159    reply.type = X_Reply;
1160    reply.sequenceNumber = client->sequence;
1161    reply.length = 0;
1162    reply.size = crtc->gammaSize;
1163    if (client->swapped) {
1164	swaps (&reply.sequenceNumber, n);
1165	swapl (&reply.length, n);
1166	swaps (&reply.size, n);
1167    }
1168    WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
1169    return client->noClientException;
1170}
1171
1172int
1173ProcRRGetCrtcGamma (ClientPtr client)
1174{
1175    REQUEST(xRRGetCrtcGammaReq);
1176    xRRGetCrtcGammaReply	reply;
1177    RRCrtcPtr			crtc;
1178    int				n;
1179    unsigned long		len;
1180    char			*extra = NULL;
1181
1182    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1183    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
1184    if (!crtc)
1185	return RRErrorBase + BadRRCrtc;
1186
1187    len = crtc->gammaSize * 3 * 2;
1188
1189    if (crtc->gammaSize) {
1190	extra = xalloc(len);
1191	if (!extra)
1192	    return BadAlloc;
1193    }
1194
1195    reply.type = X_Reply;
1196    reply.sequenceNumber = client->sequence;
1197    reply.length = (len + 3) >> 2;
1198    reply.size = crtc->gammaSize;
1199    if (client->swapped) {
1200	swaps (&reply.sequenceNumber, n);
1201	swapl (&reply.length, n);
1202	swaps (&reply.size, n);
1203    }
1204    WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
1205    if (crtc->gammaSize)
1206    {
1207	memcpy(extra, crtc->gammaRed, len);
1208	client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
1209	WriteSwappedDataToClient (client, len, extra);
1210	xfree(extra);
1211    }
1212    return client->noClientException;
1213}
1214
1215int
1216ProcRRSetCrtcGamma (ClientPtr client)
1217{
1218    REQUEST(xRRSetCrtcGammaReq);
1219    RRCrtcPtr			crtc;
1220    unsigned long		len;
1221    CARD16			*red, *green, *blue;
1222
1223    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1224    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1225    if (!crtc)
1226	return RRErrorBase + BadRRCrtc;
1227
1228    len = client->req_len - (sizeof (xRRSetCrtcGammaReq) >> 2);
1229    if (len < (stuff->size * 3 + 1) >> 1)
1230	return BadLength;
1231
1232    if (stuff->size != crtc->gammaSize)
1233	return BadMatch;
1234
1235    red = (CARD16 *) (stuff + 1);
1236    green = red + crtc->gammaSize;
1237    blue = green + crtc->gammaSize;
1238
1239    RRCrtcGammaSet (crtc, red, green, blue);
1240
1241    return Success;
1242}
1243
1244/* Version 1.3 additions */
1245
1246int
1247ProcRRSetCrtcTransform (ClientPtr client)
1248{
1249    REQUEST(xRRSetCrtcTransformReq);
1250    RRCrtcPtr		    crtc;
1251    PictTransform	    transform;
1252    struct pixman_f_transform f_transform, f_inverse;
1253    char		    *filter;
1254    int			    nbytes;
1255    xFixed		    *params;
1256    int			    nparams;
1257
1258    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1259    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1260    if (!crtc)
1261	return RRErrorBase + BadRRCrtc;
1262
1263    PictTransform_from_xRenderTransform (&transform, &stuff->transform);
1264    pixman_f_transform_from_pixman_transform (&f_transform, &transform);
1265    if (!pixman_f_transform_invert (&f_inverse, &f_transform))
1266	return BadMatch;
1267
1268    filter = (char *) (stuff + 1);
1269    nbytes = stuff->nbytesFilter;
1270    params = (xFixed *) (filter + ((nbytes + 3) & ~3));
1271    nparams = ((xFixed *) stuff + client->req_len) - params;
1272    if (nparams < 0)
1273	return BadLength;
1274
1275    return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
1276			       filter, nbytes, params, nparams);
1277}
1278
1279
1280#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1281
1282static int
1283transform_filter_length (RRTransformPtr transform)
1284{
1285    int	nbytes, nparams;
1286
1287    if (transform->filter == NULL)
1288	return 0;
1289    nbytes = strlen (transform->filter->name);
1290    nparams = transform->nparams;
1291    return ((nbytes + 3) & ~3) + (nparams * sizeof (xFixed));
1292}
1293
1294static int
1295transform_filter_encode (ClientPtr client, char *output,
1296			 CARD16	*nbytesFilter,
1297			 CARD16	*nparamsFilter,
1298			 RRTransformPtr transform)
1299{
1300    int	    nbytes, nparams;
1301    int	    n;
1302
1303    if (transform->filter == NULL) {
1304	*nbytesFilter = 0;
1305	*nparamsFilter = 0;
1306	return 0;
1307    }
1308    nbytes = strlen (transform->filter->name);
1309    nparams = transform->nparams;
1310    *nbytesFilter = nbytes;
1311    *nparamsFilter = nparams;
1312    memcpy (output, transform->filter->name, nbytes);
1313    while ((nbytes & 3) != 0)
1314	output[nbytes++] = 0;
1315    memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
1316    if (client->swapped) {
1317	swaps (nbytesFilter, n);
1318	swaps (nparamsFilter, n);
1319	SwapLongs ((CARD32 *) (output + nbytes), nparams);
1320    }
1321    nbytes += nparams * sizeof (xFixed);
1322    return nbytes;
1323}
1324
1325static void
1326transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
1327{
1328    xRenderTransform_from_PictTransform (wire, pict);
1329    if (client->swapped)
1330	SwapLongs ((CARD32 *) wire, sizeof (xRenderTransform) >> 2);
1331}
1332
1333int
1334ProcRRGetCrtcTransform (ClientPtr client)
1335{
1336    REQUEST(xRRGetCrtcTransformReq);
1337    xRRGetCrtcTransformReply	*reply;
1338    RRCrtcPtr			crtc;
1339    int				n, nextra;
1340    RRTransformPtr		current, pending;
1341    char			*extra;
1342
1343    REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
1344    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1345    if (!crtc)
1346	return RRErrorBase + BadRRCrtc;
1347
1348    pending = &crtc->client_pending_transform;
1349    current = &crtc->client_current_transform;
1350
1351    nextra = (transform_filter_length (pending) +
1352	      transform_filter_length (current));
1353
1354    reply = xalloc (sizeof (xRRGetCrtcTransformReply) + nextra);
1355    if (!reply)
1356	return BadAlloc;
1357
1358    extra = (char *) (reply + 1);
1359    reply->type = X_Reply;
1360    reply->sequenceNumber = client->sequence;
1361    reply->length = (CrtcTransformExtra + nextra) >> 2;
1362
1363    reply->hasTransforms = crtc->transforms;
1364
1365    transform_encode (client, &reply->pendingTransform, &pending->transform);
1366    extra += transform_filter_encode (client, extra,
1367				      &reply->pendingNbytesFilter,
1368				      &reply->pendingNparamsFilter,
1369				      pending);
1370
1371    transform_encode (client, &reply->currentTransform, &current->transform);
1372    extra += transform_filter_encode (client, extra,
1373				      &reply->currentNbytesFilter,
1374				      &reply->currentNparamsFilter,
1375				      current);
1376
1377    if (client->swapped) {
1378	swaps (&reply->sequenceNumber, n);
1379	swapl (&reply->length, n);
1380    }
1381    WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
1382    xfree(reply);
1383    return client->noClientException;
1384}
1385