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