rrcrtc.c revision 52397711
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    pScrPriv->lastSetTime = time;
971
972sendReply:
973    if (outputs)
974	xfree (outputs);
975
976    rep.type = X_Reply;
977    /* rep.status has already been filled in */
978    rep.length = 0;
979    rep.sequenceNumber = client->sequence;
980    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
981
982    if (client->swapped)
983    {
984	int n;
985    	swaps(&rep.sequenceNumber, n);
986    	swapl(&rep.length, n);
987	swapl(&rep.newTimestamp, n);
988    }
989    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
990
991    return client->noClientException;
992}
993
994int
995ProcRRGetPanning (ClientPtr client)
996{
997    REQUEST(xRRGetPanningReq);
998    xRRGetPanningReply	rep;
999    RRCrtcPtr		crtc;
1000    ScreenPtr		pScreen;
1001    rrScrPrivPtr	pScrPriv;
1002    BoxRec		total;
1003    BoxRec		tracking;
1004    INT16		border[4];
1005    int			n;
1006
1007    REQUEST_SIZE_MATCH(xRRGetPanningReq);
1008    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
1009
1010    if (!crtc)
1011	return RRErrorBase + BadRRCrtc;
1012
1013    /* All crtcs must be associated with screens before client
1014     * requests are processed
1015     */
1016    pScreen = crtc->pScreen;
1017    pScrPriv = rrGetScrPriv(pScreen);
1018
1019    if (!pScrPriv)
1020	return RRErrorBase + BadRRCrtc;
1021
1022    memset(&rep, 0, sizeof(rep));
1023    rep.type = X_Reply;
1024    rep.status = RRSetConfigSuccess;
1025    rep.sequenceNumber = client->sequence;
1026    rep.length = 1;
1027    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
1028
1029    if (pScrPriv->rrGetPanning &&
1030	pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
1031	rep.left          = total.x1;
1032	rep.top           = total.y1;
1033	rep.width         = total.x2 - total.x1;
1034	rep.height        = total.y2 - total.y1;
1035	rep.track_left    = tracking.x1;
1036	rep.track_top     = tracking.y1;
1037	rep.track_width   = tracking.x2 - tracking.x1;
1038	rep.track_height  = tracking.y2 - tracking.y1;
1039	rep.border_left   = border[0];
1040	rep.border_top    = border[1];
1041	rep.border_right  = border[2];
1042	rep.border_bottom = border[3];
1043    }
1044
1045    if (client->swapped) {
1046	swaps(&rep.sequenceNumber, n);
1047	swapl(&rep.length, n);
1048	swaps(&rep.timestamp, n);
1049	swaps(&rep.left, n);
1050	swaps(&rep.top, n);
1051	swaps(&rep.width, n);
1052	swaps(&rep.height, n);
1053	swaps(&rep.track_left, n);
1054	swaps(&rep.track_top, n);
1055	swaps(&rep.track_width, n);
1056	swaps(&rep.track_height, n);
1057	swaps(&rep.border_left, n);
1058	swaps(&rep.border_top, n);
1059	swaps(&rep.border_right, n);
1060	swaps(&rep.border_bottom, n);
1061    }
1062    WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
1063    return client->noClientException;
1064}
1065
1066int
1067ProcRRSetPanning (ClientPtr client)
1068{
1069    REQUEST(xRRSetPanningReq);
1070    xRRSetPanningReply	rep;
1071    RRCrtcPtr		crtc;
1072    ScreenPtr		pScreen;
1073    rrScrPrivPtr	pScrPriv;
1074    TimeStamp		time;
1075    BoxRec		total;
1076    BoxRec		tracking;
1077    INT16		border[4];
1078    int			n;
1079
1080    REQUEST_SIZE_MATCH(xRRSetPanningReq);
1081    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
1082
1083    if (!crtc)
1084	return RRErrorBase + BadRRCrtc;
1085
1086
1087    /* All crtcs must be associated with screens before client
1088     * requests are processed
1089     */
1090    pScreen = crtc->pScreen;
1091    pScrPriv = rrGetScrPriv(pScreen);
1092
1093    if (!pScrPriv) {
1094	time = currentTime;
1095	rep.status = RRSetConfigFailed;
1096	goto sendReply;
1097    }
1098
1099    time = ClientTimeToServerTime(stuff->timestamp);
1100
1101    /*
1102     * Make sure the requested set-time is not older than
1103     * the last set-time
1104     */
1105    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
1106    {
1107	rep.status = RRSetConfigInvalidTime;
1108	goto sendReply;
1109    }
1110
1111    if (!pScrPriv->rrGetPanning)
1112	return RRErrorBase + BadRRCrtc;
1113
1114    total.x1    = stuff->left;
1115    total.y1    = stuff->top;
1116    total.x2    = total.x1 + stuff->width;
1117    total.y2    = total.y1 + stuff->height;
1118    tracking.x1 = stuff->track_left;
1119    tracking.y1 = stuff->track_top;
1120    tracking.x2 = tracking.x1 + stuff->track_width;
1121    tracking.y2 = tracking.y1 + stuff->track_height;
1122    border[0]   = stuff->border_left;
1123    border[1]   = stuff->border_top;
1124    border[2]   = stuff->border_right;
1125    border[3]   = stuff->border_bottom;
1126
1127    if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
1128	return BadMatch;
1129
1130    pScrPriv->lastSetTime = time;
1131
1132    rep.status = RRSetConfigSuccess;
1133
1134sendReply:
1135    rep.type = X_Reply;
1136    rep.sequenceNumber = client->sequence;
1137    rep.length = 0;
1138    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
1139
1140    if (client->swapped) {
1141	swaps(&rep.sequenceNumber, n);
1142	swapl(&rep.length, n);
1143	swaps(&rep.newTimestamp, n);
1144    }
1145    WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
1146    return client->noClientException;
1147}
1148
1149int
1150ProcRRGetCrtcGammaSize (ClientPtr client)
1151{
1152    REQUEST(xRRGetCrtcGammaSizeReq);
1153    xRRGetCrtcGammaSizeReply	reply;
1154    RRCrtcPtr			crtc;
1155    int				n;
1156
1157    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1158    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
1159    if (!crtc)
1160	return RRErrorBase + BadRRCrtc;
1161
1162    reply.type = X_Reply;
1163    reply.sequenceNumber = client->sequence;
1164    reply.length = 0;
1165    reply.size = crtc->gammaSize;
1166    if (client->swapped) {
1167	swaps (&reply.sequenceNumber, n);
1168	swapl (&reply.length, n);
1169	swaps (&reply.size, n);
1170    }
1171    WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
1172    return client->noClientException;
1173}
1174
1175int
1176ProcRRGetCrtcGamma (ClientPtr client)
1177{
1178    REQUEST(xRRGetCrtcGammaReq);
1179    xRRGetCrtcGammaReply	reply;
1180    RRCrtcPtr			crtc;
1181    int				n;
1182    unsigned long		len;
1183    char			*extra = NULL;
1184
1185    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1186    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
1187    if (!crtc)
1188	return RRErrorBase + BadRRCrtc;
1189
1190    len = crtc->gammaSize * 3 * 2;
1191
1192    if (crtc->gammaSize) {
1193	extra = xalloc(len);
1194	if (!extra)
1195	    return BadAlloc;
1196    }
1197
1198    reply.type = X_Reply;
1199    reply.sequenceNumber = client->sequence;
1200    reply.length = (len + 3) >> 2;
1201    reply.size = crtc->gammaSize;
1202    if (client->swapped) {
1203	swaps (&reply.sequenceNumber, n);
1204	swapl (&reply.length, n);
1205	swaps (&reply.size, n);
1206    }
1207    WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
1208    if (crtc->gammaSize)
1209    {
1210	memcpy(extra, crtc->gammaRed, len);
1211	client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
1212	WriteSwappedDataToClient (client, len, extra);
1213	xfree(extra);
1214    }
1215    return client->noClientException;
1216}
1217
1218int
1219ProcRRSetCrtcGamma (ClientPtr client)
1220{
1221    REQUEST(xRRSetCrtcGammaReq);
1222    RRCrtcPtr			crtc;
1223    unsigned long		len;
1224    CARD16			*red, *green, *blue;
1225
1226    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1227    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1228    if (!crtc)
1229	return RRErrorBase + BadRRCrtc;
1230
1231    len = client->req_len - (sizeof (xRRSetCrtcGammaReq) >> 2);
1232    if (len < (stuff->size * 3 + 1) >> 1)
1233	return BadLength;
1234
1235    if (stuff->size != crtc->gammaSize)
1236	return BadMatch;
1237
1238    red = (CARD16 *) (stuff + 1);
1239    green = red + crtc->gammaSize;
1240    blue = green + crtc->gammaSize;
1241
1242    RRCrtcGammaSet (crtc, red, green, blue);
1243
1244    return Success;
1245}
1246
1247/* Version 1.3 additions */
1248
1249int
1250ProcRRSetCrtcTransform (ClientPtr client)
1251{
1252    REQUEST(xRRSetCrtcTransformReq);
1253    RRCrtcPtr		    crtc;
1254    PictTransform	    transform;
1255    struct pixman_f_transform f_transform, f_inverse;
1256    char		    *filter;
1257    int			    nbytes;
1258    xFixed		    *params;
1259    int			    nparams;
1260
1261    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1262    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1263    if (!crtc)
1264	return RRErrorBase + BadRRCrtc;
1265
1266    PictTransform_from_xRenderTransform (&transform, &stuff->transform);
1267    pixman_f_transform_from_pixman_transform (&f_transform, &transform);
1268    if (!pixman_f_transform_invert (&f_inverse, &f_transform))
1269	return BadMatch;
1270
1271    filter = (char *) (stuff + 1);
1272    nbytes = stuff->nbytesFilter;
1273    params = (xFixed *) (filter + ((nbytes + 3) & ~3));
1274    nparams = ((xFixed *) stuff + client->req_len) - params;
1275    if (nparams < 0)
1276	return BadLength;
1277
1278    return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
1279			       filter, nbytes, params, nparams);
1280}
1281
1282
1283#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1284
1285static int
1286transform_filter_length (RRTransformPtr transform)
1287{
1288    int	nbytes, nparams;
1289
1290    if (transform->filter == NULL)
1291	return 0;
1292    nbytes = strlen (transform->filter->name);
1293    nparams = transform->nparams;
1294    return ((nbytes + 3) & ~3) + (nparams * sizeof (xFixed));
1295}
1296
1297static int
1298transform_filter_encode (ClientPtr client, char *output,
1299			 CARD16	*nbytesFilter,
1300			 CARD16	*nparamsFilter,
1301			 RRTransformPtr transform)
1302{
1303    int	    nbytes, nparams;
1304    int	    n;
1305
1306    if (transform->filter == NULL) {
1307	*nbytesFilter = 0;
1308	*nparamsFilter = 0;
1309	return 0;
1310    }
1311    nbytes = strlen (transform->filter->name);
1312    nparams = transform->nparams;
1313    *nbytesFilter = nbytes;
1314    *nparamsFilter = nparams;
1315    memcpy (output, transform->filter->name, nbytes);
1316    while ((nbytes & 3) != 0)
1317	output[nbytes++] = 0;
1318    memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
1319    if (client->swapped) {
1320	swaps (nbytesFilter, n);
1321	swaps (nparamsFilter, n);
1322	SwapLongs ((CARD32 *) (output + nbytes), nparams);
1323    }
1324    nbytes += nparams * sizeof (xFixed);
1325    return nbytes;
1326}
1327
1328static void
1329transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
1330{
1331    xRenderTransform_from_PictTransform (wire, pict);
1332    if (client->swapped)
1333	SwapLongs ((CARD32 *) wire, sizeof (xRenderTransform) >> 2);
1334}
1335
1336int
1337ProcRRGetCrtcTransform (ClientPtr client)
1338{
1339    REQUEST(xRRGetCrtcTransformReq);
1340    xRRGetCrtcTransformReply	*reply;
1341    RRCrtcPtr			crtc;
1342    int				n, nextra;
1343    RRTransformPtr		current, pending;
1344    char			*extra;
1345
1346    REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
1347    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
1348    if (!crtc)
1349	return RRErrorBase + BadRRCrtc;
1350
1351    pending = &crtc->client_pending_transform;
1352    current = &crtc->client_current_transform;
1353
1354    nextra = (transform_filter_length (pending) +
1355	      transform_filter_length (current));
1356
1357    reply = xalloc (sizeof (xRRGetCrtcTransformReply) + nextra);
1358    if (!reply)
1359	return BadAlloc;
1360
1361    extra = (char *) (reply + 1);
1362    reply->type = X_Reply;
1363    reply->sequenceNumber = client->sequence;
1364    reply->length = (CrtcTransformExtra + nextra) >> 2;
1365
1366    reply->hasTransforms = crtc->transforms;
1367
1368    transform_encode (client, &reply->pendingTransform, &pending->transform);
1369    extra += transform_filter_encode (client, extra,
1370				      &reply->pendingNbytesFilter,
1371				      &reply->pendingNparamsFilter,
1372				      pending);
1373
1374    transform_encode (client, &reply->currentTransform, &current->transform);
1375    extra += transform_filter_encode (client, extra,
1376				      &reply->currentNbytesFilter,
1377				      &reply->currentNparamsFilter,
1378				      current);
1379
1380    if (client->swapped) {
1381	swaps (&reply->sequenceNumber, n);
1382	swapl (&reply->length, n);
1383    }
1384    WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
1385    xfree(reply);
1386    return client->noClientException;
1387}
1388