xref: /OK3568_Linux_fs/external/xserver/randr/rrcrtc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2006 Keith Packard
3*4882a593Smuzhiyun  * Copyright 2010 Red Hat, Inc
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun  * documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun  * the above copyright notice appear in all copies and that both that copyright
8*4882a593Smuzhiyun  * notice and this permission notice appear in supporting documentation, and
9*4882a593Smuzhiyun  * that the name of the copyright holders not be used in advertising or
10*4882a593Smuzhiyun  * publicity pertaining to distribution of the software without specific,
11*4882a593Smuzhiyun  * written prior permission.  The copyright holders make no representations
12*4882a593Smuzhiyun  * about the suitability of this software for any purpose.  It is provided "as
13*4882a593Smuzhiyun  * is" without express or implied warranty.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*4882a593Smuzhiyun  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17*4882a593Smuzhiyun  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18*4882a593Smuzhiyun  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19*4882a593Smuzhiyun  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20*4882a593Smuzhiyun  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21*4882a593Smuzhiyun  * OF THIS SOFTWARE.
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "randrstr.h"
25*4882a593Smuzhiyun #include "swaprep.h"
26*4882a593Smuzhiyun #include "mipointer.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <X11/Xatom.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun RESTYPE RRCrtcType;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * Notify the CRTC of some change
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun void
RRCrtcChanged(RRCrtcPtr crtc,Bool layoutChanged)36*4882a593Smuzhiyun RRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun     crtc->changed = TRUE;
41*4882a593Smuzhiyun     if (pScreen) {
42*4882a593Smuzhiyun         rrScrPriv(pScreen);
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun         RRSetChanged(pScreen);
45*4882a593Smuzhiyun         /*
46*4882a593Smuzhiyun          * Send ConfigureNotify on any layout change
47*4882a593Smuzhiyun          */
48*4882a593Smuzhiyun         if (layoutChanged)
49*4882a593Smuzhiyun             pScrPriv->layoutChanged = TRUE;
50*4882a593Smuzhiyun     }
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun  * Create a CRTC
55*4882a593Smuzhiyun  */
56*4882a593Smuzhiyun RRCrtcPtr
RRCrtcCreate(ScreenPtr pScreen,void * devPrivate)57*4882a593Smuzhiyun RRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun     RRCrtcPtr crtc;
60*4882a593Smuzhiyun     RRCrtcPtr *crtcs;
61*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun     if (!RRInit())
64*4882a593Smuzhiyun         return NULL;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun     /* make space for the crtc pointer */
69*4882a593Smuzhiyun     crtcs = reallocarray(pScrPriv->crtcs,
70*4882a593Smuzhiyun             pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr));
71*4882a593Smuzhiyun     if (!crtcs)
72*4882a593Smuzhiyun         return NULL;
73*4882a593Smuzhiyun     pScrPriv->crtcs = crtcs;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun     crtc = calloc(1, sizeof(RRCrtcRec));
76*4882a593Smuzhiyun     if (!crtc)
77*4882a593Smuzhiyun         return NULL;
78*4882a593Smuzhiyun     crtc->id = FakeClientID(0);
79*4882a593Smuzhiyun     crtc->pScreen = pScreen;
80*4882a593Smuzhiyun     crtc->mode = NULL;
81*4882a593Smuzhiyun     crtc->x = 0;
82*4882a593Smuzhiyun     crtc->y = 0;
83*4882a593Smuzhiyun     crtc->rotation = RR_Rotate_0;
84*4882a593Smuzhiyun     crtc->rotations = RR_Rotate_0;
85*4882a593Smuzhiyun     crtc->outputs = NULL;
86*4882a593Smuzhiyun     crtc->numOutputs = 0;
87*4882a593Smuzhiyun     crtc->gammaSize = 0;
88*4882a593Smuzhiyun     crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
89*4882a593Smuzhiyun     crtc->changed = FALSE;
90*4882a593Smuzhiyun     crtc->devPrivate = devPrivate;
91*4882a593Smuzhiyun     RRTransformInit(&crtc->client_pending_transform);
92*4882a593Smuzhiyun     RRTransformInit(&crtc->client_current_transform);
93*4882a593Smuzhiyun     pixman_transform_init_identity(&crtc->transform);
94*4882a593Smuzhiyun     pixman_f_transform_init_identity(&crtc->f_transform);
95*4882a593Smuzhiyun     pixman_f_transform_init_identity(&crtc->f_inverse);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun     if (!AddResource(crtc->id, RRCrtcType, (void *) crtc))
98*4882a593Smuzhiyun         return NULL;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun     /* attach the screen and crtc together */
101*4882a593Smuzhiyun     crtc->pScreen = pScreen;
102*4882a593Smuzhiyun     pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun     RRResourcesChanged(pScreen);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun     return crtc;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun  * Set the allowed rotations on a CRTC
111*4882a593Smuzhiyun  */
112*4882a593Smuzhiyun void
RRCrtcSetRotations(RRCrtcPtr crtc,Rotation rotations)113*4882a593Smuzhiyun RRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun     crtc->rotations = rotations;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /*
119*4882a593Smuzhiyun  * Set whether transforms are allowed on a CRTC
120*4882a593Smuzhiyun  */
121*4882a593Smuzhiyun void
RRCrtcSetTransformSupport(RRCrtcPtr crtc,Bool transforms)122*4882a593Smuzhiyun RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun     crtc->transforms = transforms;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun  * Notify the extension that the Crtc has been reconfigured,
129*4882a593Smuzhiyun  * the driver calls this whenever it has updated the mode
130*4882a593Smuzhiyun  */
131*4882a593Smuzhiyun Bool
RRCrtcNotify(RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,RRTransformPtr transform,int numOutputs,RROutputPtr * outputs)132*4882a593Smuzhiyun RRCrtcNotify(RRCrtcPtr crtc,
133*4882a593Smuzhiyun              RRModePtr mode,
134*4882a593Smuzhiyun              int x,
135*4882a593Smuzhiyun              int y,
136*4882a593Smuzhiyun              Rotation rotation,
137*4882a593Smuzhiyun              RRTransformPtr transform, int numOutputs, RROutputPtr * outputs)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun     int i, j;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun     /*
142*4882a593Smuzhiyun      * Check to see if any of the new outputs were
143*4882a593Smuzhiyun      * not in the old list and mark them as changed
144*4882a593Smuzhiyun      */
145*4882a593Smuzhiyun     for (i = 0; i < numOutputs; i++) {
146*4882a593Smuzhiyun         for (j = 0; j < crtc->numOutputs; j++)
147*4882a593Smuzhiyun             if (outputs[i] == crtc->outputs[j])
148*4882a593Smuzhiyun                 break;
149*4882a593Smuzhiyun         if (j == crtc->numOutputs) {
150*4882a593Smuzhiyun             outputs[i]->crtc = crtc;
151*4882a593Smuzhiyun             RROutputChanged(outputs[i], FALSE);
152*4882a593Smuzhiyun             RRCrtcChanged(crtc, FALSE);
153*4882a593Smuzhiyun         }
154*4882a593Smuzhiyun     }
155*4882a593Smuzhiyun     /*
156*4882a593Smuzhiyun      * Check to see if any of the old outputs are
157*4882a593Smuzhiyun      * not in the new list and mark them as changed
158*4882a593Smuzhiyun      */
159*4882a593Smuzhiyun     for (j = 0; j < crtc->numOutputs; j++) {
160*4882a593Smuzhiyun         for (i = 0; i < numOutputs; i++)
161*4882a593Smuzhiyun             if (outputs[i] == crtc->outputs[j])
162*4882a593Smuzhiyun                 break;
163*4882a593Smuzhiyun         if (i == numOutputs) {
164*4882a593Smuzhiyun             if (crtc->outputs[j]->crtc == crtc)
165*4882a593Smuzhiyun                 crtc->outputs[j]->crtc = NULL;
166*4882a593Smuzhiyun             RROutputChanged(crtc->outputs[j], FALSE);
167*4882a593Smuzhiyun             RRCrtcChanged(crtc, FALSE);
168*4882a593Smuzhiyun         }
169*4882a593Smuzhiyun     }
170*4882a593Smuzhiyun     /*
171*4882a593Smuzhiyun      * Reallocate the crtc output array if necessary
172*4882a593Smuzhiyun      */
173*4882a593Smuzhiyun     if (numOutputs != crtc->numOutputs) {
174*4882a593Smuzhiyun         RROutputPtr *newoutputs;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun         if (numOutputs) {
177*4882a593Smuzhiyun             if (crtc->numOutputs)
178*4882a593Smuzhiyun                 newoutputs = reallocarray(crtc->outputs,
179*4882a593Smuzhiyun                                           numOutputs, sizeof(RROutputPtr));
180*4882a593Smuzhiyun             else
181*4882a593Smuzhiyun                 newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr));
182*4882a593Smuzhiyun             if (!newoutputs)
183*4882a593Smuzhiyun                 return FALSE;
184*4882a593Smuzhiyun         }
185*4882a593Smuzhiyun         else {
186*4882a593Smuzhiyun             free(crtc->outputs);
187*4882a593Smuzhiyun             newoutputs = NULL;
188*4882a593Smuzhiyun         }
189*4882a593Smuzhiyun         crtc->outputs = newoutputs;
190*4882a593Smuzhiyun         crtc->numOutputs = numOutputs;
191*4882a593Smuzhiyun     }
192*4882a593Smuzhiyun     /*
193*4882a593Smuzhiyun      * Copy the new list of outputs into the crtc
194*4882a593Smuzhiyun      */
195*4882a593Smuzhiyun     memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr));
196*4882a593Smuzhiyun     /*
197*4882a593Smuzhiyun      * Update remaining crtc fields
198*4882a593Smuzhiyun      */
199*4882a593Smuzhiyun     if (mode != crtc->mode) {
200*4882a593Smuzhiyun         if (crtc->mode)
201*4882a593Smuzhiyun             RRModeDestroy(crtc->mode);
202*4882a593Smuzhiyun         crtc->mode = mode;
203*4882a593Smuzhiyun         if (mode != NULL)
204*4882a593Smuzhiyun             mode->refcnt++;
205*4882a593Smuzhiyun         RRCrtcChanged(crtc, TRUE);
206*4882a593Smuzhiyun     }
207*4882a593Smuzhiyun     if (x != crtc->x) {
208*4882a593Smuzhiyun         crtc->x = x;
209*4882a593Smuzhiyun         RRCrtcChanged(crtc, TRUE);
210*4882a593Smuzhiyun     }
211*4882a593Smuzhiyun     if (y != crtc->y) {
212*4882a593Smuzhiyun         crtc->y = y;
213*4882a593Smuzhiyun         RRCrtcChanged(crtc, TRUE);
214*4882a593Smuzhiyun     }
215*4882a593Smuzhiyun     if (rotation != crtc->rotation) {
216*4882a593Smuzhiyun         crtc->rotation = rotation;
217*4882a593Smuzhiyun         RRCrtcChanged(crtc, TRUE);
218*4882a593Smuzhiyun     }
219*4882a593Smuzhiyun     if (!RRTransformEqual(transform, &crtc->client_current_transform)) {
220*4882a593Smuzhiyun         RRTransformCopy(&crtc->client_current_transform, transform);
221*4882a593Smuzhiyun         RRCrtcChanged(crtc, TRUE);
222*4882a593Smuzhiyun     }
223*4882a593Smuzhiyun     if (crtc->changed && mode) {
224*4882a593Smuzhiyun         RRTransformCompute(x, y,
225*4882a593Smuzhiyun                            mode->mode.width, mode->mode.height,
226*4882a593Smuzhiyun                            rotation,
227*4882a593Smuzhiyun                            &crtc->client_current_transform,
228*4882a593Smuzhiyun                            &crtc->transform, &crtc->f_transform,
229*4882a593Smuzhiyun                            &crtc->f_inverse);
230*4882a593Smuzhiyun     }
231*4882a593Smuzhiyun     return TRUE;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun void
RRDeliverCrtcEvent(ClientPtr client,WindowPtr pWin,RRCrtcPtr crtc)235*4882a593Smuzhiyun RRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun     rrScrPriv(pScreen);
240*4882a593Smuzhiyun     RRModePtr mode = crtc->mode;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun     xRRCrtcChangeNotifyEvent ce = {
243*4882a593Smuzhiyun         .type = RRNotify + RREventBase,
244*4882a593Smuzhiyun         .subCode = RRNotify_CrtcChange,
245*4882a593Smuzhiyun         .timestamp = pScrPriv->lastSetTime.milliseconds,
246*4882a593Smuzhiyun         .window = pWin->drawable.id,
247*4882a593Smuzhiyun         .crtc = crtc->id,
248*4882a593Smuzhiyun         .mode = mode ? mode->mode.id : None,
249*4882a593Smuzhiyun         .rotation = crtc->rotation,
250*4882a593Smuzhiyun         .x = mode ? crtc->x : 0,
251*4882a593Smuzhiyun         .y = mode ? crtc->y : 0,
252*4882a593Smuzhiyun         .width = mode ? mode->mode.width : 0,
253*4882a593Smuzhiyun         .height = mode ? mode->mode.height : 0
254*4882a593Smuzhiyun     };
255*4882a593Smuzhiyun     WriteEventsToClient(client, 1, (xEvent *) &ce);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static Bool
RRCrtcPendingProperties(RRCrtcPtr crtc)259*4882a593Smuzhiyun RRCrtcPendingProperties(RRCrtcPtr crtc)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun     rrScrPriv(pScreen);
264*4882a593Smuzhiyun     int o;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun     for (o = 0; o < pScrPriv->numOutputs; o++) {
267*4882a593Smuzhiyun         RROutputPtr output = pScrPriv->outputs[o];
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun         if (output->crtc == crtc && output->pendingProperties)
270*4882a593Smuzhiyun             return TRUE;
271*4882a593Smuzhiyun     }
272*4882a593Smuzhiyun     return FALSE;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun static Bool
cursor_bounds(RRCrtcPtr crtc,int * left,int * right,int * top,int * bottom)276*4882a593Smuzhiyun cursor_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun     rrScrPriv(crtc->pScreen);
279*4882a593Smuzhiyun     BoxRec bounds;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun     if (crtc->mode == NULL)
282*4882a593Smuzhiyun 	return FALSE;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun     memset(&bounds, 0, sizeof(bounds));
285*4882a593Smuzhiyun     if (pScrPriv->rrGetPanning)
286*4882a593Smuzhiyun 	pScrPriv->rrGetPanning(crtc->pScreen, crtc, NULL, &bounds, NULL);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun     if (bounds.y2 <= bounds.y1 || bounds.x2 <= bounds.x1) {
289*4882a593Smuzhiyun 	bounds.x1 = 0;
290*4882a593Smuzhiyun 	bounds.y1 = 0;
291*4882a593Smuzhiyun 	bounds.x2 = crtc->mode->mode.width;
292*4882a593Smuzhiyun 	bounds.y2 = crtc->mode->mode.height;
293*4882a593Smuzhiyun     }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun     pixman_f_transform_bounds(&crtc->f_transform, &bounds);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun     *left = bounds.x1;
298*4882a593Smuzhiyun     *right = bounds.x2;
299*4882a593Smuzhiyun     *top = bounds.y1;
300*4882a593Smuzhiyun     *bottom = bounds.y2;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun     return TRUE;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun /* overlapping counts as adjacent */
306*4882a593Smuzhiyun static Bool
crtcs_adjacent(const RRCrtcPtr a,const RRCrtcPtr b)307*4882a593Smuzhiyun crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun     /* left, right, top, bottom... */
310*4882a593Smuzhiyun     int al, ar, at, ab;
311*4882a593Smuzhiyun     int bl, br, bt, bb;
312*4882a593Smuzhiyun     int cl, cr, ct, cb;         /* the overlap, if any */
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun     if (!cursor_bounds(a, &al, &ar, &at, &ab))
315*4882a593Smuzhiyun 	    return FALSE;
316*4882a593Smuzhiyun     if (!cursor_bounds(b, &bl, &br, &bt, &bb))
317*4882a593Smuzhiyun 	    return FALSE;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun     cl = max(al, bl);
320*4882a593Smuzhiyun     cr = min(ar, br);
321*4882a593Smuzhiyun     ct = max(at, bt);
322*4882a593Smuzhiyun     cb = min(ab, bb);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun     return (cl <= cr) && (ct <= cb);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun /* Depth-first search and mark all CRTCs reachable from cur */
328*4882a593Smuzhiyun static void
mark_crtcs(rrScrPrivPtr pScrPriv,int * reachable,int cur)329*4882a593Smuzhiyun mark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun     int i;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun     reachable[cur] = TRUE;
334*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; ++i) {
335*4882a593Smuzhiyun         if (reachable[i])
336*4882a593Smuzhiyun             continue;
337*4882a593Smuzhiyun         if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
338*4882a593Smuzhiyun             mark_crtcs(pScrPriv, reachable, i);
339*4882a593Smuzhiyun     }
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun static void
RRComputeContiguity(ScreenPtr pScreen)343*4882a593Smuzhiyun RRComputeContiguity(ScreenPtr pScreen)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun     rrScrPriv(pScreen);
346*4882a593Smuzhiyun     Bool discontiguous = TRUE;
347*4882a593Smuzhiyun     int i, n = pScrPriv->numCrtcs;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun     int *reachable = calloc(n, sizeof(int));
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun     if (!reachable)
352*4882a593Smuzhiyun         goto out;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun     /* Find first enabled CRTC and start search for reachable CRTCs from it */
355*4882a593Smuzhiyun     for (i = 0; i < n; ++i) {
356*4882a593Smuzhiyun         if (pScrPriv->crtcs[i]->mode) {
357*4882a593Smuzhiyun             mark_crtcs(pScrPriv, reachable, i);
358*4882a593Smuzhiyun             break;
359*4882a593Smuzhiyun         }
360*4882a593Smuzhiyun     }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun     /* Check that all enabled CRTCs were marked as reachable */
363*4882a593Smuzhiyun     for (i = 0; i < n; ++i)
364*4882a593Smuzhiyun         if (pScrPriv->crtcs[i]->mode && !reachable[i])
365*4882a593Smuzhiyun             goto out;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun     discontiguous = FALSE;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun  out:
370*4882a593Smuzhiyun     free(reachable);
371*4882a593Smuzhiyun     pScrPriv->discontiguous = discontiguous;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun static void
rrDestroySharedPixmap(RRCrtcPtr crtc,PixmapPtr pPixmap)375*4882a593Smuzhiyun rrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) {
376*4882a593Smuzhiyun     ScreenPtr master = crtc->pScreen->current_master;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun     if (master && pPixmap->master_pixmap) {
379*4882a593Smuzhiyun         /*
380*4882a593Smuzhiyun          * Unref the pixmap twice: once for the original reference, and once
381*4882a593Smuzhiyun          * for the reference implicitly added by PixmapShareToSlave.
382*4882a593Smuzhiyun          */
383*4882a593Smuzhiyun         PixmapUnshareSlavePixmap(pPixmap);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun         master->DestroyPixmap(pPixmap->master_pixmap);
386*4882a593Smuzhiyun         master->DestroyPixmap(pPixmap->master_pixmap);
387*4882a593Smuzhiyun     }
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun     crtc->pScreen->DestroyPixmap(pPixmap);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun void
RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)393*4882a593Smuzhiyun RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun     rrScrPriv(crtc->pScreen);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun     if (crtc->scanout_pixmap) {
398*4882a593Smuzhiyun         ScreenPtr master = crtc->pScreen->current_master;
399*4882a593Smuzhiyun         DrawablePtr mrootdraw = &master->root->drawable;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun         if (crtc->scanout_pixmap_back) {
402*4882a593Smuzhiyun             pScrPriv->rrDisableSharedPixmapFlipping(crtc);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun             if (mrootdraw) {
405*4882a593Smuzhiyun                 master->StopFlippingPixmapTracking(mrootdraw,
406*4882a593Smuzhiyun                                                    crtc->scanout_pixmap,
407*4882a593Smuzhiyun                                                    crtc->scanout_pixmap_back);
408*4882a593Smuzhiyun             }
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun             rrDestroySharedPixmap(crtc, crtc->scanout_pixmap_back);
411*4882a593Smuzhiyun             crtc->scanout_pixmap_back = NULL;
412*4882a593Smuzhiyun         }
413*4882a593Smuzhiyun         else {
414*4882a593Smuzhiyun             pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun             if (mrootdraw) {
417*4882a593Smuzhiyun                 master->StopPixmapTracking(mrootdraw,
418*4882a593Smuzhiyun                                            crtc->scanout_pixmap);
419*4882a593Smuzhiyun             }
420*4882a593Smuzhiyun         }
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun         rrDestroySharedPixmap(crtc, crtc->scanout_pixmap);
423*4882a593Smuzhiyun         crtc->scanout_pixmap = NULL;
424*4882a593Smuzhiyun     }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun     RRCrtcChanged(crtc, TRUE);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun static PixmapPtr
rrCreateSharedPixmap(RRCrtcPtr crtc,ScreenPtr master,int width,int height,int depth,int x,int y,Rotation rotation)430*4882a593Smuzhiyun rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr master,
431*4882a593Smuzhiyun                      int width, int height, int depth,
432*4882a593Smuzhiyun                      int x, int y, Rotation rotation)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun     PixmapPtr mpix, spix;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun     mpix = master->CreatePixmap(master, width, height, depth,
437*4882a593Smuzhiyun                                 CREATE_PIXMAP_USAGE_SHARED);
438*4882a593Smuzhiyun     if (!mpix)
439*4882a593Smuzhiyun         return NULL;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun     spix = PixmapShareToSlave(mpix, crtc->pScreen);
442*4882a593Smuzhiyun     if (spix == NULL) {
443*4882a593Smuzhiyun         master->DestroyPixmap(mpix);
444*4882a593Smuzhiyun         return NULL;
445*4882a593Smuzhiyun     }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun     return spix;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun static Bool
rrGetPixmapSharingSyncProp(int numOutputs,RROutputPtr * outputs)451*4882a593Smuzhiyun rrGetPixmapSharingSyncProp(int numOutputs, RROutputPtr * outputs)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun     /* Determine if the user wants prime syncing */
454*4882a593Smuzhiyun     int o;
455*4882a593Smuzhiyun     const char *syncStr = PRIME_SYNC_PROP;
456*4882a593Smuzhiyun     Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
457*4882a593Smuzhiyun     if (syncProp == None)
458*4882a593Smuzhiyun         return TRUE;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun     /* If one output doesn't want sync, no sync */
461*4882a593Smuzhiyun     for (o = 0; o < numOutputs; o++) {
462*4882a593Smuzhiyun         RRPropertyValuePtr val;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun         /* Try pending value first, then current value */
465*4882a593Smuzhiyun         if ((val = RRGetOutputProperty(outputs[o], syncProp, TRUE)) &&
466*4882a593Smuzhiyun             val->data) {
467*4882a593Smuzhiyun             if (!(*(char *) val->data))
468*4882a593Smuzhiyun                 return FALSE;
469*4882a593Smuzhiyun             continue;
470*4882a593Smuzhiyun         }
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun         if ((val = RRGetOutputProperty(outputs[o], syncProp, FALSE)) &&
473*4882a593Smuzhiyun             val->data) {
474*4882a593Smuzhiyun             if (!(*(char *) val->data))
475*4882a593Smuzhiyun                 return FALSE;
476*4882a593Smuzhiyun             continue;
477*4882a593Smuzhiyun         }
478*4882a593Smuzhiyun     }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun     return TRUE;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun static void
rrSetPixmapSharingSyncProp(char val,int numOutputs,RROutputPtr * outputs)484*4882a593Smuzhiyun rrSetPixmapSharingSyncProp(char val, int numOutputs, RROutputPtr * outputs)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun     int o;
487*4882a593Smuzhiyun     const char *syncStr = PRIME_SYNC_PROP;
488*4882a593Smuzhiyun     Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE);
489*4882a593Smuzhiyun     if (syncProp == None)
490*4882a593Smuzhiyun         return;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun     for (o = 0; o < numOutputs; o++) {
493*4882a593Smuzhiyun         RRPropertyPtr prop = RRQueryOutputProperty(outputs[o], syncProp);
494*4882a593Smuzhiyun         if (prop)
495*4882a593Smuzhiyun             RRChangeOutputProperty(outputs[o], syncProp, XA_INTEGER,
496*4882a593Smuzhiyun                                    8, PropModeReplace, 1, &val, FALSE, TRUE);
497*4882a593Smuzhiyun     }
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun static Bool
rrSetupPixmapSharing(RRCrtcPtr crtc,int width,int height,int x,int y,Rotation rotation,Bool sync,int numOutputs,RROutputPtr * outputs)501*4882a593Smuzhiyun rrSetupPixmapSharing(RRCrtcPtr crtc, int width, int height,
502*4882a593Smuzhiyun                      int x, int y, Rotation rotation, Bool sync,
503*4882a593Smuzhiyun                      int numOutputs, RROutputPtr * outputs)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun     ScreenPtr master = crtc->pScreen->current_master;
506*4882a593Smuzhiyun     rrScrPrivPtr pMasterScrPriv = rrGetScrPriv(master);
507*4882a593Smuzhiyun     rrScrPrivPtr pSlaveScrPriv = rrGetScrPriv(crtc->pScreen);
508*4882a593Smuzhiyun     DrawablePtr mrootdraw = &master->root->drawable;
509*4882a593Smuzhiyun     int depth = mrootdraw->depth;
510*4882a593Smuzhiyun     PixmapPtr spix_front;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun     /* Create a pixmap on the master screen, then get a shared handle for it.
513*4882a593Smuzhiyun        Create a shared pixmap on the slave screen using the handle.
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun        If sync == FALSE --
516*4882a593Smuzhiyun        Set slave screen to scanout shared linear pixmap.
517*4882a593Smuzhiyun        Set the master screen to do dirty updates to the shared pixmap
518*4882a593Smuzhiyun        from the screen pixmap on its own accord.
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun        If sync == TRUE --
521*4882a593Smuzhiyun        If any of the below steps fail, clean up and fall back to sync == FALSE.
522*4882a593Smuzhiyun        Create another shared pixmap on the slave screen using the handle.
523*4882a593Smuzhiyun        Set slave screen to prepare for scanout and flipping between shared
524*4882a593Smuzhiyun        linear pixmaps.
525*4882a593Smuzhiyun        Set the master screen to do dirty updates to the shared pixmaps from the
526*4882a593Smuzhiyun        screen pixmap when prompted to by us or the slave.
527*4882a593Smuzhiyun        Prompt the master to do a dirty update on the first shared pixmap, then
528*4882a593Smuzhiyun        defer to the slave.
529*4882a593Smuzhiyun     */
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun     if (crtc->scanout_pixmap)
532*4882a593Smuzhiyun         RRCrtcDetachScanoutPixmap(crtc);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun     if (width == 0 && height == 0) {
535*4882a593Smuzhiyun         return TRUE;
536*4882a593Smuzhiyun     }
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun     spix_front = rrCreateSharedPixmap(crtc, master,
539*4882a593Smuzhiyun                                       width, height, depth,
540*4882a593Smuzhiyun                                       x, y, rotation);
541*4882a593Smuzhiyun     if (spix_front == NULL) {
542*4882a593Smuzhiyun         ErrorF("randr: failed to create shared pixmap\n");
543*4882a593Smuzhiyun         return FALSE;
544*4882a593Smuzhiyun     }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun     /* Both source and sink must support required ABI funcs for flipping */
547*4882a593Smuzhiyun     if (sync &&
548*4882a593Smuzhiyun         pSlaveScrPriv->rrEnableSharedPixmapFlipping &&
549*4882a593Smuzhiyun         pSlaveScrPriv->rrDisableSharedPixmapFlipping &&
550*4882a593Smuzhiyun         pMasterScrPriv->rrStartFlippingPixmapTracking &&
551*4882a593Smuzhiyun         master->PresentSharedPixmap &&
552*4882a593Smuzhiyun         master->StopFlippingPixmapTracking) {
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun         PixmapPtr spix_back = rrCreateSharedPixmap(crtc, master,
555*4882a593Smuzhiyun                                                    width, height, depth,
556*4882a593Smuzhiyun                                                    x, y, rotation);
557*4882a593Smuzhiyun         if (spix_back == NULL)
558*4882a593Smuzhiyun             goto fail;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun         if (!pSlaveScrPriv->rrEnableSharedPixmapFlipping(crtc,
561*4882a593Smuzhiyun                                                          spix_front, spix_back))
562*4882a593Smuzhiyun             goto fail;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun         crtc->scanout_pixmap = spix_front;
565*4882a593Smuzhiyun         crtc->scanout_pixmap_back = spix_back;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun         if (!pMasterScrPriv->rrStartFlippingPixmapTracking(crtc,
568*4882a593Smuzhiyun                                                            mrootdraw,
569*4882a593Smuzhiyun                                                            spix_front,
570*4882a593Smuzhiyun                                                            spix_back,
571*4882a593Smuzhiyun                                                            x, y, 0, 0,
572*4882a593Smuzhiyun                                                            rotation)) {
573*4882a593Smuzhiyun             pSlaveScrPriv->rrDisableSharedPixmapFlipping(crtc);
574*4882a593Smuzhiyun             goto fail;
575*4882a593Smuzhiyun         }
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun         master->PresentSharedPixmap(spix_front);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun         return TRUE;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun fail: /* If flipping funcs fail, just fall back to unsynchronized */
582*4882a593Smuzhiyun         if (spix_back)
583*4882a593Smuzhiyun             rrDestroySharedPixmap(crtc, spix_back);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun         crtc->scanout_pixmap = NULL;
586*4882a593Smuzhiyun         crtc->scanout_pixmap_back = NULL;
587*4882a593Smuzhiyun     }
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun     if (sync) { /* Wanted sync, didn't get it */
590*4882a593Smuzhiyun         ErrorF("randr: falling back to unsynchronized pixmap sharing\n");
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun         /* Set output property to 0 to indicate to user */
593*4882a593Smuzhiyun         rrSetPixmapSharingSyncProp(0, numOutputs, outputs);
594*4882a593Smuzhiyun     }
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun     if (!pSlaveScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
597*4882a593Smuzhiyun         rrDestroySharedPixmap(crtc, spix_front);
598*4882a593Smuzhiyun         ErrorF("randr: failed to set shadow slave pixmap\n");
599*4882a593Smuzhiyun         return FALSE;
600*4882a593Smuzhiyun     }
601*4882a593Smuzhiyun     crtc->scanout_pixmap = spix_front;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun     master->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun     return TRUE;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
crtc_to_box(BoxPtr box,RRCrtcPtr crtc)608*4882a593Smuzhiyun static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun     box->x1 = crtc->x;
611*4882a593Smuzhiyun     box->y1 = crtc->y;
612*4882a593Smuzhiyun     switch (crtc->rotation) {
613*4882a593Smuzhiyun     case RR_Rotate_0:
614*4882a593Smuzhiyun     case RR_Rotate_180:
615*4882a593Smuzhiyun     default:
616*4882a593Smuzhiyun         box->x2 = crtc->x + crtc->mode->mode.width;
617*4882a593Smuzhiyun         box->y2 = crtc->y + crtc->mode->mode.height;
618*4882a593Smuzhiyun         break;
619*4882a593Smuzhiyun     case RR_Rotate_90:
620*4882a593Smuzhiyun     case RR_Rotate_270:
621*4882a593Smuzhiyun         box->x2 = crtc->x + crtc->mode->mode.height;
622*4882a593Smuzhiyun         box->y2 = crtc->y + crtc->mode->mode.width;
623*4882a593Smuzhiyun         break;
624*4882a593Smuzhiyun     }
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun static Bool
rrCheckPixmapBounding(ScreenPtr pScreen,RRCrtcPtr rr_crtc,Rotation rotation,int x,int y,int w,int h)628*4882a593Smuzhiyun rrCheckPixmapBounding(ScreenPtr pScreen,
629*4882a593Smuzhiyun                       RRCrtcPtr rr_crtc, Rotation rotation,
630*4882a593Smuzhiyun                       int x, int y, int w, int h)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun     RegionRec root_pixmap_region, total_region, new_crtc_region;
633*4882a593Smuzhiyun     int c;
634*4882a593Smuzhiyun     BoxRec newbox;
635*4882a593Smuzhiyun     BoxPtr newsize;
636*4882a593Smuzhiyun     ScreenPtr slave;
637*4882a593Smuzhiyun     int new_width, new_height;
638*4882a593Smuzhiyun     PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
639*4882a593Smuzhiyun     rrScrPriv(pScreen);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun     PixmapRegionInit(&root_pixmap_region, screen_pixmap);
642*4882a593Smuzhiyun     RegionInit(&total_region, NULL, 0);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun     /* have to iterate all the crtcs of the attached gpu masters
645*4882a593Smuzhiyun        and all their output slaves */
646*4882a593Smuzhiyun     for (c = 0; c < pScrPriv->numCrtcs; c++) {
647*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[c];
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun         if (crtc == rr_crtc) {
650*4882a593Smuzhiyun             newbox.x1 = x;
651*4882a593Smuzhiyun             newbox.y1 = y;
652*4882a593Smuzhiyun             if (rotation == RR_Rotate_90 ||
653*4882a593Smuzhiyun                 rotation == RR_Rotate_270) {
654*4882a593Smuzhiyun                 newbox.x2 = x + h;
655*4882a593Smuzhiyun                 newbox.y2 = y + w;
656*4882a593Smuzhiyun             } else {
657*4882a593Smuzhiyun                 newbox.x2 = x + w;
658*4882a593Smuzhiyun                 newbox.y2 = y + h;
659*4882a593Smuzhiyun             }
660*4882a593Smuzhiyun         } else {
661*4882a593Smuzhiyun             if (!crtc->mode)
662*4882a593Smuzhiyun                 continue;
663*4882a593Smuzhiyun             crtc_to_box(&newbox, crtc);
664*4882a593Smuzhiyun         }
665*4882a593Smuzhiyun         RegionInit(&new_crtc_region, &newbox, 1);
666*4882a593Smuzhiyun         RegionUnion(&total_region, &total_region, &new_crtc_region);
667*4882a593Smuzhiyun     }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun     xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
670*4882a593Smuzhiyun         rrScrPrivPtr    slave_priv = rrGetScrPriv(slave);
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun         if (!slave->is_output_slave)
673*4882a593Smuzhiyun             continue;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun         for (c = 0; c < slave_priv->numCrtcs; c++) {
676*4882a593Smuzhiyun             RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun             if (slave_crtc == rr_crtc) {
679*4882a593Smuzhiyun                 newbox.x1 = x;
680*4882a593Smuzhiyun                 newbox.y1 = y;
681*4882a593Smuzhiyun                 if (rotation == RR_Rotate_90 ||
682*4882a593Smuzhiyun                     rotation == RR_Rotate_270) {
683*4882a593Smuzhiyun                     newbox.x2 = x + h;
684*4882a593Smuzhiyun                     newbox.y2 = y + w;
685*4882a593Smuzhiyun                 } else {
686*4882a593Smuzhiyun                     newbox.x2 = x + w;
687*4882a593Smuzhiyun                     newbox.y2 = y + h;
688*4882a593Smuzhiyun                 }
689*4882a593Smuzhiyun             }
690*4882a593Smuzhiyun             else {
691*4882a593Smuzhiyun                 if (!slave_crtc->mode)
692*4882a593Smuzhiyun                     continue;
693*4882a593Smuzhiyun                 crtc_to_box(&newbox, slave_crtc);
694*4882a593Smuzhiyun             }
695*4882a593Smuzhiyun             RegionInit(&new_crtc_region, &newbox, 1);
696*4882a593Smuzhiyun             RegionUnion(&total_region, &total_region, &new_crtc_region);
697*4882a593Smuzhiyun         }
698*4882a593Smuzhiyun     }
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun     newsize = RegionExtents(&total_region);
701*4882a593Smuzhiyun     new_width = newsize->x2;
702*4882a593Smuzhiyun     new_height = newsize->y2;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun     if (new_width < screen_pixmap->drawable.width)
705*4882a593Smuzhiyun         new_width = screen_pixmap->drawable.width;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun     if (new_height < screen_pixmap->drawable.height)
708*4882a593Smuzhiyun         new_height = screen_pixmap->drawable.height;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun     if (new_width <= screen_pixmap->drawable.width &&
711*4882a593Smuzhiyun         new_height <= screen_pixmap->drawable.height) {
712*4882a593Smuzhiyun     } else {
713*4882a593Smuzhiyun         pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
714*4882a593Smuzhiyun     }
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun     /* set shatters TODO */
717*4882a593Smuzhiyun     return TRUE;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun /*
721*4882a593Smuzhiyun  * Request that the Crtc be reconfigured
722*4882a593Smuzhiyun  */
723*4882a593Smuzhiyun Bool
RRCrtcSet(RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,int numOutputs,RROutputPtr * outputs)724*4882a593Smuzhiyun RRCrtcSet(RRCrtcPtr crtc,
725*4882a593Smuzhiyun           RRModePtr mode,
726*4882a593Smuzhiyun           int x,
727*4882a593Smuzhiyun           int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
730*4882a593Smuzhiyun     Bool ret = FALSE;
731*4882a593Smuzhiyun     Bool recompute = TRUE;
732*4882a593Smuzhiyun     Bool crtcChanged;
733*4882a593Smuzhiyun     int  o;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun     rrScrPriv(pScreen);
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun     crtcChanged = FALSE;
738*4882a593Smuzhiyun     for (o = 0; o < numOutputs; o++) {
739*4882a593Smuzhiyun         if (outputs[o] && outputs[o]->crtc != crtc) {
740*4882a593Smuzhiyun             crtcChanged = TRUE;
741*4882a593Smuzhiyun             break;
742*4882a593Smuzhiyun         }
743*4882a593Smuzhiyun     }
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun     /* See if nothing changed */
746*4882a593Smuzhiyun     if (crtc->mode == mode &&
747*4882a593Smuzhiyun         crtc->x == x &&
748*4882a593Smuzhiyun         crtc->y == y &&
749*4882a593Smuzhiyun         crtc->rotation == rotation &&
750*4882a593Smuzhiyun         crtc->numOutputs == numOutputs &&
751*4882a593Smuzhiyun         !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
752*4882a593Smuzhiyun         !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
753*4882a593Smuzhiyun         !crtcChanged) {
754*4882a593Smuzhiyun         recompute = FALSE;
755*4882a593Smuzhiyun         ret = TRUE;
756*4882a593Smuzhiyun     }
757*4882a593Smuzhiyun     else {
758*4882a593Smuzhiyun         if (pScreen->isGPU) {
759*4882a593Smuzhiyun             ScreenPtr master = pScreen->current_master;
760*4882a593Smuzhiyun             int width = 0, height = 0;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun             if (mode) {
763*4882a593Smuzhiyun                 width = mode->mode.width;
764*4882a593Smuzhiyun                 height = mode->mode.height;
765*4882a593Smuzhiyun             }
766*4882a593Smuzhiyun             ret = rrCheckPixmapBounding(master, crtc,
767*4882a593Smuzhiyun                                         rotation, x, y, width, height);
768*4882a593Smuzhiyun             if (!ret)
769*4882a593Smuzhiyun                 return FALSE;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun             if (pScreen->current_master) {
772*4882a593Smuzhiyun                 Bool sync = rrGetPixmapSharingSyncProp(numOutputs, outputs);
773*4882a593Smuzhiyun                 ret = rrSetupPixmapSharing(crtc, width, height,
774*4882a593Smuzhiyun                                            x, y, rotation, sync,
775*4882a593Smuzhiyun                                            numOutputs, outputs);
776*4882a593Smuzhiyun             }
777*4882a593Smuzhiyun         }
778*4882a593Smuzhiyun #if RANDR_12_INTERFACE
779*4882a593Smuzhiyun         if (pScrPriv->rrCrtcSet) {
780*4882a593Smuzhiyun             ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
781*4882a593Smuzhiyun                                           rotation, numOutputs, outputs);
782*4882a593Smuzhiyun         }
783*4882a593Smuzhiyun         else
784*4882a593Smuzhiyun #endif
785*4882a593Smuzhiyun         {
786*4882a593Smuzhiyun #if RANDR_10_INTERFACE
787*4882a593Smuzhiyun             if (pScrPriv->rrSetConfig) {
788*4882a593Smuzhiyun                 RRScreenSize size;
789*4882a593Smuzhiyun                 RRScreenRate rate;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun                 if (!mode) {
792*4882a593Smuzhiyun                     RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
793*4882a593Smuzhiyun                     ret = TRUE;
794*4882a593Smuzhiyun                 }
795*4882a593Smuzhiyun                 else {
796*4882a593Smuzhiyun                     size.width = mode->mode.width;
797*4882a593Smuzhiyun                     size.height = mode->mode.height;
798*4882a593Smuzhiyun                     if (outputs[0]->mmWidth && outputs[0]->mmHeight) {
799*4882a593Smuzhiyun                         size.mmWidth = outputs[0]->mmWidth;
800*4882a593Smuzhiyun                         size.mmHeight = outputs[0]->mmHeight;
801*4882a593Smuzhiyun                     }
802*4882a593Smuzhiyun                     else {
803*4882a593Smuzhiyun                         size.mmWidth = pScreen->mmWidth;
804*4882a593Smuzhiyun                         size.mmHeight = pScreen->mmHeight;
805*4882a593Smuzhiyun                     }
806*4882a593Smuzhiyun                     size.nRates = 1;
807*4882a593Smuzhiyun                     rate.rate = RRVerticalRefresh(&mode->mode);
808*4882a593Smuzhiyun                     size.pRates = &rate;
809*4882a593Smuzhiyun                     ret =
810*4882a593Smuzhiyun                         (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate,
811*4882a593Smuzhiyun                                                   &size);
812*4882a593Smuzhiyun                     /*
813*4882a593Smuzhiyun                      * Old 1.0 interface tied screen size to mode size
814*4882a593Smuzhiyun                      */
815*4882a593Smuzhiyun                     if (ret) {
816*4882a593Smuzhiyun                         RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
817*4882a593Smuzhiyun                                      outputs);
818*4882a593Smuzhiyun                         RRScreenSizeNotify(pScreen);
819*4882a593Smuzhiyun                     }
820*4882a593Smuzhiyun                 }
821*4882a593Smuzhiyun             }
822*4882a593Smuzhiyun #endif
823*4882a593Smuzhiyun         }
824*4882a593Smuzhiyun         if (ret) {
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun             RRTellChanged(pScreen);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun             for (o = 0; o < numOutputs; o++)
829*4882a593Smuzhiyun                 RRPostPendingProperties(outputs[o]);
830*4882a593Smuzhiyun         }
831*4882a593Smuzhiyun     }
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun     if (recompute)
834*4882a593Smuzhiyun         RRComputeContiguity(pScreen);
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun     return ret;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun /*
840*4882a593Smuzhiyun  * Return crtc transform
841*4882a593Smuzhiyun  */
842*4882a593Smuzhiyun RRTransformPtr
RRCrtcGetTransform(RRCrtcPtr crtc)843*4882a593Smuzhiyun RRCrtcGetTransform(RRCrtcPtr crtc)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun     RRTransformPtr transform = &crtc->client_pending_transform;
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun     if (pixman_transform_is_identity(&transform->transform))
848*4882a593Smuzhiyun         return NULL;
849*4882a593Smuzhiyun     return transform;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun /*
853*4882a593Smuzhiyun  * Check whether the pending and current transforms are the same
854*4882a593Smuzhiyun  */
855*4882a593Smuzhiyun Bool
RRCrtcPendingTransform(RRCrtcPtr crtc)856*4882a593Smuzhiyun RRCrtcPendingTransform(RRCrtcPtr crtc)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun     return !RRTransformEqual(&crtc->client_current_transform,
859*4882a593Smuzhiyun                              &crtc->client_pending_transform);
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun /*
863*4882a593Smuzhiyun  * Destroy a Crtc at shutdown
864*4882a593Smuzhiyun  */
865*4882a593Smuzhiyun void
RRCrtcDestroy(RRCrtcPtr crtc)866*4882a593Smuzhiyun RRCrtcDestroy(RRCrtcPtr crtc)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun     FreeResource(crtc->id, 0);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun static int
RRCrtcDestroyResource(void * value,XID pid)872*4882a593Smuzhiyun RRCrtcDestroyResource(void *value, XID pid)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun     RRCrtcPtr crtc = (RRCrtcPtr) value;
875*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun     if (pScreen) {
878*4882a593Smuzhiyun         rrScrPriv(pScreen);
879*4882a593Smuzhiyun         int i;
880*4882a593Smuzhiyun         RRLeasePtr lease, next;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun         xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) {
883*4882a593Smuzhiyun             int c;
884*4882a593Smuzhiyun             for (c = 0; c < lease->numCrtcs; c++) {
885*4882a593Smuzhiyun                 if (lease->crtcs[c] == crtc) {
886*4882a593Smuzhiyun                     RRTerminateLease(lease);
887*4882a593Smuzhiyun                     break;
888*4882a593Smuzhiyun                 }
889*4882a593Smuzhiyun             }
890*4882a593Smuzhiyun         }
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun         for (i = 0; i < pScrPriv->numCrtcs; i++) {
893*4882a593Smuzhiyun             if (pScrPriv->crtcs[i] == crtc) {
894*4882a593Smuzhiyun                 memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
895*4882a593Smuzhiyun                         (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr));
896*4882a593Smuzhiyun                 --pScrPriv->numCrtcs;
897*4882a593Smuzhiyun                 break;
898*4882a593Smuzhiyun             }
899*4882a593Smuzhiyun         }
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun         RRResourcesChanged(pScreen);
902*4882a593Smuzhiyun     }
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun     if (crtc->scanout_pixmap)
905*4882a593Smuzhiyun         RRCrtcDetachScanoutPixmap(crtc);
906*4882a593Smuzhiyun     free(crtc->gammaRed);
907*4882a593Smuzhiyun     if (crtc->mode)
908*4882a593Smuzhiyun         RRModeDestroy(crtc->mode);
909*4882a593Smuzhiyun     free(crtc->outputs);
910*4882a593Smuzhiyun     free(crtc);
911*4882a593Smuzhiyun     return 1;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun /*
915*4882a593Smuzhiyun  * Request that the Crtc gamma be changed
916*4882a593Smuzhiyun  */
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun Bool
RRCrtcGammaSet(RRCrtcPtr crtc,CARD16 * red,CARD16 * green,CARD16 * blue)919*4882a593Smuzhiyun RRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun     Bool ret = TRUE;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun #if RANDR_12_INTERFACE
924*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
925*4882a593Smuzhiyun #endif
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun     memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16));
928*4882a593Smuzhiyun     memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16));
929*4882a593Smuzhiyun     memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16));
930*4882a593Smuzhiyun #if RANDR_12_INTERFACE
931*4882a593Smuzhiyun     if (pScreen) {
932*4882a593Smuzhiyun         rrScrPriv(pScreen);
933*4882a593Smuzhiyun         if (pScrPriv->rrCrtcSetGamma)
934*4882a593Smuzhiyun             ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
935*4882a593Smuzhiyun     }
936*4882a593Smuzhiyun #endif
937*4882a593Smuzhiyun     return ret;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun /*
941*4882a593Smuzhiyun  * Request current gamma back from the DDX (if possible).
942*4882a593Smuzhiyun  * This includes gamma size.
943*4882a593Smuzhiyun  */
944*4882a593Smuzhiyun Bool
RRCrtcGammaGet(RRCrtcPtr crtc)945*4882a593Smuzhiyun RRCrtcGammaGet(RRCrtcPtr crtc)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun     Bool ret = TRUE;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun #if RANDR_12_INTERFACE
950*4882a593Smuzhiyun     ScreenPtr pScreen = crtc->pScreen;
951*4882a593Smuzhiyun #endif
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun #if RANDR_12_INTERFACE
954*4882a593Smuzhiyun     if (pScreen) {
955*4882a593Smuzhiyun         rrScrPriv(pScreen);
956*4882a593Smuzhiyun         if (pScrPriv->rrCrtcGetGamma)
957*4882a593Smuzhiyun             ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
958*4882a593Smuzhiyun     }
959*4882a593Smuzhiyun #endif
960*4882a593Smuzhiyun     return ret;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun /*
964*4882a593Smuzhiyun  * Notify the extension that the Crtc gamma has been changed
965*4882a593Smuzhiyun  * The driver calls this whenever it has changed the gamma values
966*4882a593Smuzhiyun  * in the RRCrtcRec
967*4882a593Smuzhiyun  */
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun Bool
RRCrtcGammaNotify(RRCrtcPtr crtc)970*4882a593Smuzhiyun RRCrtcGammaNotify(RRCrtcPtr crtc)
971*4882a593Smuzhiyun {
972*4882a593Smuzhiyun     return TRUE;                /* not much going on here */
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun static void
RRModeGetScanoutSize(RRModePtr mode,PictTransformPtr transform,int * width,int * height)976*4882a593Smuzhiyun RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
977*4882a593Smuzhiyun                      int *width, int *height)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun     BoxRec box;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun     if (mode == NULL) {
982*4882a593Smuzhiyun         *width = 0;
983*4882a593Smuzhiyun         *height = 0;
984*4882a593Smuzhiyun         return;
985*4882a593Smuzhiyun     }
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun     box.x1 = 0;
988*4882a593Smuzhiyun     box.y1 = 0;
989*4882a593Smuzhiyun     box.x2 = mode->mode.width;
990*4882a593Smuzhiyun     box.y2 = mode->mode.height;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun     pixman_transform_bounds(transform, &box);
993*4882a593Smuzhiyun     *width = box.x2 - box.x1;
994*4882a593Smuzhiyun     *height = box.y2 - box.y1;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun /**
998*4882a593Smuzhiyun  * Returns the width/height that the crtc scans out from the framebuffer
999*4882a593Smuzhiyun  */
1000*4882a593Smuzhiyun void
RRCrtcGetScanoutSize(RRCrtcPtr crtc,int * width,int * height)1001*4882a593Smuzhiyun RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun     RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun /*
1007*4882a593Smuzhiyun  * Set the size of the gamma table at server startup time
1008*4882a593Smuzhiyun  */
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun Bool
RRCrtcGammaSetSize(RRCrtcPtr crtc,int size)1011*4882a593Smuzhiyun RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun     CARD16 *gamma;
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun     if (size == crtc->gammaSize)
1016*4882a593Smuzhiyun         return TRUE;
1017*4882a593Smuzhiyun     if (size) {
1018*4882a593Smuzhiyun         gamma = xallocarray(size, 3 * sizeof(CARD16));
1019*4882a593Smuzhiyun         if (!gamma)
1020*4882a593Smuzhiyun             return FALSE;
1021*4882a593Smuzhiyun     }
1022*4882a593Smuzhiyun     else
1023*4882a593Smuzhiyun         gamma = NULL;
1024*4882a593Smuzhiyun     free(crtc->gammaRed);
1025*4882a593Smuzhiyun     crtc->gammaRed = gamma;
1026*4882a593Smuzhiyun     crtc->gammaGreen = gamma + size;
1027*4882a593Smuzhiyun     crtc->gammaBlue = gamma + size * 2;
1028*4882a593Smuzhiyun     crtc->gammaSize = size;
1029*4882a593Smuzhiyun     return TRUE;
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun /*
1033*4882a593Smuzhiyun  * Set the pending CRTC transformation
1034*4882a593Smuzhiyun  */
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun int
RRCrtcTransformSet(RRCrtcPtr crtc,PictTransformPtr transform,struct pixman_f_transform * f_transform,struct pixman_f_transform * f_inverse,char * filter_name,int filter_len,xFixed * params,int nparams)1037*4882a593Smuzhiyun RRCrtcTransformSet(RRCrtcPtr crtc,
1038*4882a593Smuzhiyun                    PictTransformPtr transform,
1039*4882a593Smuzhiyun                    struct pixman_f_transform *f_transform,
1040*4882a593Smuzhiyun                    struct pixman_f_transform *f_inverse,
1041*4882a593Smuzhiyun                    char *filter_name,
1042*4882a593Smuzhiyun                    int filter_len, xFixed * params, int nparams)
1043*4882a593Smuzhiyun {
1044*4882a593Smuzhiyun     PictFilterPtr filter = NULL;
1045*4882a593Smuzhiyun     int width = 0, height = 0;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun     if (!crtc->transforms)
1048*4882a593Smuzhiyun         return BadValue;
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun     if (filter_len) {
1051*4882a593Smuzhiyun         filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
1052*4882a593Smuzhiyun         if (!filter)
1053*4882a593Smuzhiyun             return BadName;
1054*4882a593Smuzhiyun         if (filter->ValidateParams) {
1055*4882a593Smuzhiyun             if (!filter->ValidateParams(crtc->pScreen, filter->id,
1056*4882a593Smuzhiyun                                         params, nparams, &width, &height))
1057*4882a593Smuzhiyun                 return BadMatch;
1058*4882a593Smuzhiyun         }
1059*4882a593Smuzhiyun         else {
1060*4882a593Smuzhiyun             width = filter->width;
1061*4882a593Smuzhiyun             height = filter->height;
1062*4882a593Smuzhiyun         }
1063*4882a593Smuzhiyun     }
1064*4882a593Smuzhiyun     else {
1065*4882a593Smuzhiyun         if (nparams)
1066*4882a593Smuzhiyun             return BadMatch;
1067*4882a593Smuzhiyun     }
1068*4882a593Smuzhiyun     if (!RRTransformSetFilter(&crtc->client_pending_transform,
1069*4882a593Smuzhiyun                               filter, params, nparams, width, height))
1070*4882a593Smuzhiyun         return BadAlloc;
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun     crtc->client_pending_transform.transform = *transform;
1073*4882a593Smuzhiyun     crtc->client_pending_transform.f_transform = *f_transform;
1074*4882a593Smuzhiyun     crtc->client_pending_transform.f_inverse = *f_inverse;
1075*4882a593Smuzhiyun     return Success;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun /*
1079*4882a593Smuzhiyun  * Initialize crtc type
1080*4882a593Smuzhiyun  */
1081*4882a593Smuzhiyun Bool
RRCrtcInit(void)1082*4882a593Smuzhiyun RRCrtcInit(void)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun     RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
1085*4882a593Smuzhiyun     if (!RRCrtcType)
1086*4882a593Smuzhiyun         return FALSE;
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun     return TRUE;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun /*
1092*4882a593Smuzhiyun  * Initialize crtc type error value
1093*4882a593Smuzhiyun  */
1094*4882a593Smuzhiyun void
RRCrtcInitErrorValue(void)1095*4882a593Smuzhiyun RRCrtcInitErrorValue(void)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun     SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun int
ProcRRGetCrtcInfo(ClientPtr client)1101*4882a593Smuzhiyun ProcRRGetCrtcInfo(ClientPtr client)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun     REQUEST(xRRGetCrtcInfoReq);
1104*4882a593Smuzhiyun     xRRGetCrtcInfoReply rep;
1105*4882a593Smuzhiyun     RRCrtcPtr crtc;
1106*4882a593Smuzhiyun     CARD8 *extra = NULL;
1107*4882a593Smuzhiyun     unsigned long extraLen;
1108*4882a593Smuzhiyun     ScreenPtr pScreen;
1109*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
1110*4882a593Smuzhiyun     RRModePtr mode;
1111*4882a593Smuzhiyun     RROutput *outputs;
1112*4882a593Smuzhiyun     RROutput *possible;
1113*4882a593Smuzhiyun     int i, j, k;
1114*4882a593Smuzhiyun     int width, height;
1115*4882a593Smuzhiyun     BoxRec panned_area;
1116*4882a593Smuzhiyun     Bool leased;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
1119*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun     leased = RRCrtcIsLeased(crtc);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun     /* All crtcs must be associated with screens before client
1124*4882a593Smuzhiyun      * requests are processed
1125*4882a593Smuzhiyun      */
1126*4882a593Smuzhiyun     pScreen = crtc->pScreen;
1127*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun     mode = crtc->mode;
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun     rep = (xRRGetCrtcInfoReply) {
1132*4882a593Smuzhiyun         .type = X_Reply,
1133*4882a593Smuzhiyun         .status = RRSetConfigSuccess,
1134*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1135*4882a593Smuzhiyun         .length = 0,
1136*4882a593Smuzhiyun         .timestamp = pScrPriv->lastSetTime.milliseconds
1137*4882a593Smuzhiyun     };
1138*4882a593Smuzhiyun     if (leased) {
1139*4882a593Smuzhiyun         rep.x = rep.y = rep.width = rep.height = 0;
1140*4882a593Smuzhiyun         rep.mode = 0;
1141*4882a593Smuzhiyun         rep.rotation = RR_Rotate_0;
1142*4882a593Smuzhiyun         rep.rotations = RR_Rotate_0;
1143*4882a593Smuzhiyun         rep.nOutput = 0;
1144*4882a593Smuzhiyun         rep.nPossibleOutput = 0;
1145*4882a593Smuzhiyun         rep.length = 0;
1146*4882a593Smuzhiyun         extraLen = 0;
1147*4882a593Smuzhiyun     } else {
1148*4882a593Smuzhiyun         if (pScrPriv->rrGetPanning &&
1149*4882a593Smuzhiyun             pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
1150*4882a593Smuzhiyun             (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
1151*4882a593Smuzhiyun         {
1152*4882a593Smuzhiyun             rep.x = panned_area.x1;
1153*4882a593Smuzhiyun             rep.y = panned_area.y1;
1154*4882a593Smuzhiyun             rep.width = panned_area.x2 - panned_area.x1;
1155*4882a593Smuzhiyun             rep.height = panned_area.y2 - panned_area.y1;
1156*4882a593Smuzhiyun         }
1157*4882a593Smuzhiyun         else {
1158*4882a593Smuzhiyun             RRCrtcGetScanoutSize(crtc, &width, &height);
1159*4882a593Smuzhiyun             rep.x = crtc->x;
1160*4882a593Smuzhiyun             rep.y = crtc->y;
1161*4882a593Smuzhiyun             rep.width = width;
1162*4882a593Smuzhiyun             rep.height = height;
1163*4882a593Smuzhiyun         }
1164*4882a593Smuzhiyun         rep.mode = mode ? mode->mode.id : 0;
1165*4882a593Smuzhiyun         rep.rotation = crtc->rotation;
1166*4882a593Smuzhiyun         rep.rotations = crtc->rotations;
1167*4882a593Smuzhiyun         rep.nOutput = crtc->numOutputs;
1168*4882a593Smuzhiyun         k = 0;
1169*4882a593Smuzhiyun         for (i = 0; i < pScrPriv->numOutputs; i++) {
1170*4882a593Smuzhiyun             if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1171*4882a593Smuzhiyun                 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1172*4882a593Smuzhiyun                     if (pScrPriv->outputs[i]->crtcs[j] == crtc)
1173*4882a593Smuzhiyun                         k++;
1174*4882a593Smuzhiyun             }
1175*4882a593Smuzhiyun         }
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun         rep.nPossibleOutput = k;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun         rep.length = rep.nOutput + rep.nPossibleOutput;
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun         extraLen = rep.length << 2;
1182*4882a593Smuzhiyun         if (extraLen) {
1183*4882a593Smuzhiyun             extra = malloc(extraLen);
1184*4882a593Smuzhiyun             if (!extra)
1185*4882a593Smuzhiyun                 return BadAlloc;
1186*4882a593Smuzhiyun         }
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun         outputs = (RROutput *) extra;
1189*4882a593Smuzhiyun         possible = (RROutput *) (outputs + rep.nOutput);
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun         for (i = 0; i < crtc->numOutputs; i++) {
1192*4882a593Smuzhiyun             outputs[i] = crtc->outputs[i]->id;
1193*4882a593Smuzhiyun             if (client->swapped)
1194*4882a593Smuzhiyun                 swapl(&outputs[i]);
1195*4882a593Smuzhiyun         }
1196*4882a593Smuzhiyun         k = 0;
1197*4882a593Smuzhiyun         for (i = 0; i < pScrPriv->numOutputs; i++) {
1198*4882a593Smuzhiyun             if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1199*4882a593Smuzhiyun                 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1200*4882a593Smuzhiyun                     if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
1201*4882a593Smuzhiyun                         possible[k] = pScrPriv->outputs[i]->id;
1202*4882a593Smuzhiyun                         if (client->swapped)
1203*4882a593Smuzhiyun                             swapl(&possible[k]);
1204*4882a593Smuzhiyun                         k++;
1205*4882a593Smuzhiyun                     }
1206*4882a593Smuzhiyun             }
1207*4882a593Smuzhiyun         }
1208*4882a593Smuzhiyun     }
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun     if (client->swapped) {
1211*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
1212*4882a593Smuzhiyun         swapl(&rep.length);
1213*4882a593Smuzhiyun         swapl(&rep.timestamp);
1214*4882a593Smuzhiyun         swaps(&rep.x);
1215*4882a593Smuzhiyun         swaps(&rep.y);
1216*4882a593Smuzhiyun         swaps(&rep.width);
1217*4882a593Smuzhiyun         swaps(&rep.height);
1218*4882a593Smuzhiyun         swapl(&rep.mode);
1219*4882a593Smuzhiyun         swaps(&rep.rotation);
1220*4882a593Smuzhiyun         swaps(&rep.rotations);
1221*4882a593Smuzhiyun         swaps(&rep.nOutput);
1222*4882a593Smuzhiyun         swaps(&rep.nPossibleOutput);
1223*4882a593Smuzhiyun     }
1224*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
1225*4882a593Smuzhiyun     if (extraLen) {
1226*4882a593Smuzhiyun         WriteToClient(client, extraLen, extra);
1227*4882a593Smuzhiyun         free(extra);
1228*4882a593Smuzhiyun     }
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun     return Success;
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun int
ProcRRSetCrtcConfig(ClientPtr client)1234*4882a593Smuzhiyun ProcRRSetCrtcConfig(ClientPtr client)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun     REQUEST(xRRSetCrtcConfigReq);
1237*4882a593Smuzhiyun     xRRSetCrtcConfigReply rep;
1238*4882a593Smuzhiyun     ScreenPtr pScreen;
1239*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
1240*4882a593Smuzhiyun     RRCrtcPtr crtc;
1241*4882a593Smuzhiyun     RRModePtr mode;
1242*4882a593Smuzhiyun     int numOutputs;
1243*4882a593Smuzhiyun     RROutputPtr *outputs = NULL;
1244*4882a593Smuzhiyun     RROutput *outputIds;
1245*4882a593Smuzhiyun     TimeStamp time;
1246*4882a593Smuzhiyun     Rotation rotation;
1247*4882a593Smuzhiyun     int ret, i, j;
1248*4882a593Smuzhiyun     CARD8 status;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun     REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
1251*4882a593Smuzhiyun     numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun     if (RRCrtcIsLeased(crtc))
1256*4882a593Smuzhiyun         return BadAccess;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun     if (stuff->mode == None) {
1259*4882a593Smuzhiyun         mode = NULL;
1260*4882a593Smuzhiyun         if (numOutputs > 0)
1261*4882a593Smuzhiyun             return BadMatch;
1262*4882a593Smuzhiyun     }
1263*4882a593Smuzhiyun     else {
1264*4882a593Smuzhiyun         VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
1265*4882a593Smuzhiyun         if (numOutputs == 0)
1266*4882a593Smuzhiyun             return BadMatch;
1267*4882a593Smuzhiyun     }
1268*4882a593Smuzhiyun     if (numOutputs) {
1269*4882a593Smuzhiyun         outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
1270*4882a593Smuzhiyun         if (!outputs)
1271*4882a593Smuzhiyun             return BadAlloc;
1272*4882a593Smuzhiyun     }
1273*4882a593Smuzhiyun     else
1274*4882a593Smuzhiyun         outputs = NULL;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun     outputIds = (RROutput *) (stuff + 1);
1277*4882a593Smuzhiyun     for (i = 0; i < numOutputs; i++) {
1278*4882a593Smuzhiyun         ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
1279*4882a593Smuzhiyun                                      RROutputType, client, DixSetAttrAccess);
1280*4882a593Smuzhiyun         if (ret != Success) {
1281*4882a593Smuzhiyun             free(outputs);
1282*4882a593Smuzhiyun             return ret;
1283*4882a593Smuzhiyun         }
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun         if (RROutputIsLeased(outputs[i])) {
1286*4882a593Smuzhiyun             free(outputs);
1287*4882a593Smuzhiyun             return BadAccess;
1288*4882a593Smuzhiyun         }
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun         /* validate crtc for this output */
1291*4882a593Smuzhiyun         for (j = 0; j < outputs[i]->numCrtcs; j++)
1292*4882a593Smuzhiyun             if (outputs[i]->crtcs[j] == crtc)
1293*4882a593Smuzhiyun                 break;
1294*4882a593Smuzhiyun         if (j == outputs[i]->numCrtcs) {
1295*4882a593Smuzhiyun             free(outputs);
1296*4882a593Smuzhiyun             return BadMatch;
1297*4882a593Smuzhiyun         }
1298*4882a593Smuzhiyun         /* validate mode for this output */
1299*4882a593Smuzhiyun         for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
1300*4882a593Smuzhiyun             RRModePtr m = (j < outputs[i]->numModes ?
1301*4882a593Smuzhiyun                            outputs[i]->modes[j] :
1302*4882a593Smuzhiyun                            outputs[i]->userModes[j - outputs[i]->numModes]);
1303*4882a593Smuzhiyun             if (m == mode)
1304*4882a593Smuzhiyun                 break;
1305*4882a593Smuzhiyun         }
1306*4882a593Smuzhiyun         if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
1307*4882a593Smuzhiyun             free(outputs);
1308*4882a593Smuzhiyun             return BadMatch;
1309*4882a593Smuzhiyun         }
1310*4882a593Smuzhiyun     }
1311*4882a593Smuzhiyun     /* validate clones */
1312*4882a593Smuzhiyun     for (i = 0; i < numOutputs; i++) {
1313*4882a593Smuzhiyun         for (j = 0; j < numOutputs; j++) {
1314*4882a593Smuzhiyun             int k;
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun             if (i == j)
1317*4882a593Smuzhiyun                 continue;
1318*4882a593Smuzhiyun             for (k = 0; k < outputs[i]->numClones; k++) {
1319*4882a593Smuzhiyun                 if (outputs[i]->clones[k] == outputs[j])
1320*4882a593Smuzhiyun                     break;
1321*4882a593Smuzhiyun             }
1322*4882a593Smuzhiyun             if (k == outputs[i]->numClones) {
1323*4882a593Smuzhiyun                 free(outputs);
1324*4882a593Smuzhiyun                 return BadMatch;
1325*4882a593Smuzhiyun             }
1326*4882a593Smuzhiyun         }
1327*4882a593Smuzhiyun     }
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun     pScreen = crtc->pScreen;
1330*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->timestamp);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun     if (!pScrPriv) {
1335*4882a593Smuzhiyun         time = currentTime;
1336*4882a593Smuzhiyun         status = RRSetConfigFailed;
1337*4882a593Smuzhiyun         goto sendReply;
1338*4882a593Smuzhiyun     }
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun     /*
1341*4882a593Smuzhiyun      * Validate requested rotation
1342*4882a593Smuzhiyun      */
1343*4882a593Smuzhiyun     rotation = (Rotation) stuff->rotation;
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun     /* test the rotation bits only! */
1346*4882a593Smuzhiyun     switch (rotation & 0xf) {
1347*4882a593Smuzhiyun     case RR_Rotate_0:
1348*4882a593Smuzhiyun     case RR_Rotate_90:
1349*4882a593Smuzhiyun     case RR_Rotate_180:
1350*4882a593Smuzhiyun     case RR_Rotate_270:
1351*4882a593Smuzhiyun         break;
1352*4882a593Smuzhiyun     default:
1353*4882a593Smuzhiyun         /*
1354*4882a593Smuzhiyun          * Invalid rotation
1355*4882a593Smuzhiyun          */
1356*4882a593Smuzhiyun         client->errorValue = stuff->rotation;
1357*4882a593Smuzhiyun         free(outputs);
1358*4882a593Smuzhiyun         return BadValue;
1359*4882a593Smuzhiyun     }
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun     if (mode) {
1362*4882a593Smuzhiyun         if ((~crtc->rotations) & rotation) {
1363*4882a593Smuzhiyun             /*
1364*4882a593Smuzhiyun              * requested rotation or reflection not supported by screen
1365*4882a593Smuzhiyun              */
1366*4882a593Smuzhiyun             client->errorValue = stuff->rotation;
1367*4882a593Smuzhiyun             free(outputs);
1368*4882a593Smuzhiyun             return BadMatch;
1369*4882a593Smuzhiyun         }
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun #ifdef RANDR_12_INTERFACE
1372*4882a593Smuzhiyun         /*
1373*4882a593Smuzhiyun          * Check screen size bounds if the DDX provides a 1.2 interface
1374*4882a593Smuzhiyun          * for setting screen size. Else, assume the CrtcSet sets
1375*4882a593Smuzhiyun          * the size along with the mode. If the driver supports transforms,
1376*4882a593Smuzhiyun          * then it must allow crtcs to display a subset of the screen, so
1377*4882a593Smuzhiyun          * only do this check for drivers without transform support.
1378*4882a593Smuzhiyun          */
1379*4882a593Smuzhiyun         if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
1380*4882a593Smuzhiyun             int source_width;
1381*4882a593Smuzhiyun             int source_height;
1382*4882a593Smuzhiyun             PictTransform transform;
1383*4882a593Smuzhiyun             struct pixman_f_transform f_transform, f_inverse;
1384*4882a593Smuzhiyun             int width, height;
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun             if (pScreen->isGPU) {
1387*4882a593Smuzhiyun                 width = pScreen->current_master->width;
1388*4882a593Smuzhiyun                 height = pScreen->current_master->height;
1389*4882a593Smuzhiyun             }
1390*4882a593Smuzhiyun             else {
1391*4882a593Smuzhiyun                 width = pScreen->width;
1392*4882a593Smuzhiyun                 height = pScreen->height;
1393*4882a593Smuzhiyun             }
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun             RRTransformCompute(stuff->x, stuff->y,
1396*4882a593Smuzhiyun                                mode->mode.width, mode->mode.height,
1397*4882a593Smuzhiyun                                rotation,
1398*4882a593Smuzhiyun                                &crtc->client_pending_transform,
1399*4882a593Smuzhiyun                                &transform, &f_transform, &f_inverse);
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun             RRModeGetScanoutSize(mode, &transform, &source_width,
1402*4882a593Smuzhiyun                                  &source_height);
1403*4882a593Smuzhiyun             if (stuff->x + source_width > width) {
1404*4882a593Smuzhiyun                 client->errorValue = stuff->x;
1405*4882a593Smuzhiyun                 free(outputs);
1406*4882a593Smuzhiyun                 return BadValue;
1407*4882a593Smuzhiyun             }
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun             if (stuff->y + source_height > height) {
1410*4882a593Smuzhiyun                 client->errorValue = stuff->y;
1411*4882a593Smuzhiyun                 free(outputs);
1412*4882a593Smuzhiyun                 return BadValue;
1413*4882a593Smuzhiyun             }
1414*4882a593Smuzhiyun         }
1415*4882a593Smuzhiyun #endif
1416*4882a593Smuzhiyun     }
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun     if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
1419*4882a593Smuzhiyun                    rotation, numOutputs, outputs)) {
1420*4882a593Smuzhiyun         status = RRSetConfigFailed;
1421*4882a593Smuzhiyun         goto sendReply;
1422*4882a593Smuzhiyun     }
1423*4882a593Smuzhiyun     status = RRSetConfigSuccess;
1424*4882a593Smuzhiyun     pScrPriv->lastSetTime = time;
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun  sendReply:
1427*4882a593Smuzhiyun     free(outputs);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun     rep = (xRRSetCrtcConfigReply) {
1430*4882a593Smuzhiyun         .type = X_Reply,
1431*4882a593Smuzhiyun         .status = status,
1432*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1433*4882a593Smuzhiyun         .length = 0,
1434*4882a593Smuzhiyun         .newTimestamp = pScrPriv->lastSetTime.milliseconds
1435*4882a593Smuzhiyun     };
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun     if (client->swapped) {
1438*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
1439*4882a593Smuzhiyun         swapl(&rep.length);
1440*4882a593Smuzhiyun         swapl(&rep.newTimestamp);
1441*4882a593Smuzhiyun     }
1442*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun     return Success;
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun int
ProcRRGetPanning(ClientPtr client)1448*4882a593Smuzhiyun ProcRRGetPanning(ClientPtr client)
1449*4882a593Smuzhiyun {
1450*4882a593Smuzhiyun     REQUEST(xRRGetPanningReq);
1451*4882a593Smuzhiyun     xRRGetPanningReply rep;
1452*4882a593Smuzhiyun     RRCrtcPtr crtc;
1453*4882a593Smuzhiyun     ScreenPtr pScreen;
1454*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
1455*4882a593Smuzhiyun     BoxRec total;
1456*4882a593Smuzhiyun     BoxRec tracking;
1457*4882a593Smuzhiyun     INT16 border[4];
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRGetPanningReq);
1460*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun     /* All crtcs must be associated with screens before client
1463*4882a593Smuzhiyun      * requests are processed
1464*4882a593Smuzhiyun      */
1465*4882a593Smuzhiyun     pScreen = crtc->pScreen;
1466*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun     if (!pScrPriv)
1469*4882a593Smuzhiyun         return RRErrorBase + BadRRCrtc;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun     rep = (xRRGetPanningReply) {
1472*4882a593Smuzhiyun         .type = X_Reply,
1473*4882a593Smuzhiyun         .status = RRSetConfigSuccess,
1474*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1475*4882a593Smuzhiyun         .length = 1,
1476*4882a593Smuzhiyun         .timestamp = pScrPriv->lastSetTime.milliseconds
1477*4882a593Smuzhiyun     };
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun     if (pScrPriv->rrGetPanning &&
1480*4882a593Smuzhiyun         pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
1481*4882a593Smuzhiyun         rep.left = total.x1;
1482*4882a593Smuzhiyun         rep.top = total.y1;
1483*4882a593Smuzhiyun         rep.width = total.x2 - total.x1;
1484*4882a593Smuzhiyun         rep.height = total.y2 - total.y1;
1485*4882a593Smuzhiyun         rep.track_left = tracking.x1;
1486*4882a593Smuzhiyun         rep.track_top = tracking.y1;
1487*4882a593Smuzhiyun         rep.track_width = tracking.x2 - tracking.x1;
1488*4882a593Smuzhiyun         rep.track_height = tracking.y2 - tracking.y1;
1489*4882a593Smuzhiyun         rep.border_left = border[0];
1490*4882a593Smuzhiyun         rep.border_top = border[1];
1491*4882a593Smuzhiyun         rep.border_right = border[2];
1492*4882a593Smuzhiyun         rep.border_bottom = border[3];
1493*4882a593Smuzhiyun     }
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun     if (client->swapped) {
1496*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
1497*4882a593Smuzhiyun         swapl(&rep.length);
1498*4882a593Smuzhiyun         swapl(&rep.timestamp);
1499*4882a593Smuzhiyun         swaps(&rep.left);
1500*4882a593Smuzhiyun         swaps(&rep.top);
1501*4882a593Smuzhiyun         swaps(&rep.width);
1502*4882a593Smuzhiyun         swaps(&rep.height);
1503*4882a593Smuzhiyun         swaps(&rep.track_left);
1504*4882a593Smuzhiyun         swaps(&rep.track_top);
1505*4882a593Smuzhiyun         swaps(&rep.track_width);
1506*4882a593Smuzhiyun         swaps(&rep.track_height);
1507*4882a593Smuzhiyun         swaps(&rep.border_left);
1508*4882a593Smuzhiyun         swaps(&rep.border_top);
1509*4882a593Smuzhiyun         swaps(&rep.border_right);
1510*4882a593Smuzhiyun         swaps(&rep.border_bottom);
1511*4882a593Smuzhiyun     }
1512*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
1513*4882a593Smuzhiyun     return Success;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun int
ProcRRSetPanning(ClientPtr client)1517*4882a593Smuzhiyun ProcRRSetPanning(ClientPtr client)
1518*4882a593Smuzhiyun {
1519*4882a593Smuzhiyun     REQUEST(xRRSetPanningReq);
1520*4882a593Smuzhiyun     xRRSetPanningReply rep;
1521*4882a593Smuzhiyun     RRCrtcPtr crtc;
1522*4882a593Smuzhiyun     ScreenPtr pScreen;
1523*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
1524*4882a593Smuzhiyun     TimeStamp time;
1525*4882a593Smuzhiyun     BoxRec total;
1526*4882a593Smuzhiyun     BoxRec tracking;
1527*4882a593Smuzhiyun     INT16 border[4];
1528*4882a593Smuzhiyun     CARD8 status;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRSetPanningReq);
1531*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun     if (RRCrtcIsLeased(crtc))
1534*4882a593Smuzhiyun         return BadAccess;
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun     /* All crtcs must be associated with screens before client
1537*4882a593Smuzhiyun      * requests are processed
1538*4882a593Smuzhiyun      */
1539*4882a593Smuzhiyun     pScreen = crtc->pScreen;
1540*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun     if (!pScrPriv) {
1543*4882a593Smuzhiyun         time = currentTime;
1544*4882a593Smuzhiyun         status = RRSetConfigFailed;
1545*4882a593Smuzhiyun         goto sendReply;
1546*4882a593Smuzhiyun     }
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->timestamp);
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun     if (!pScrPriv->rrGetPanning)
1551*4882a593Smuzhiyun         return RRErrorBase + BadRRCrtc;
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun     total.x1 = stuff->left;
1554*4882a593Smuzhiyun     total.y1 = stuff->top;
1555*4882a593Smuzhiyun     total.x2 = total.x1 + stuff->width;
1556*4882a593Smuzhiyun     total.y2 = total.y1 + stuff->height;
1557*4882a593Smuzhiyun     tracking.x1 = stuff->track_left;
1558*4882a593Smuzhiyun     tracking.y1 = stuff->track_top;
1559*4882a593Smuzhiyun     tracking.x2 = tracking.x1 + stuff->track_width;
1560*4882a593Smuzhiyun     tracking.y2 = tracking.y1 + stuff->track_height;
1561*4882a593Smuzhiyun     border[0] = stuff->border_left;
1562*4882a593Smuzhiyun     border[1] = stuff->border_top;
1563*4882a593Smuzhiyun     border[2] = stuff->border_right;
1564*4882a593Smuzhiyun     border[3] = stuff->border_bottom;
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun     if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
1567*4882a593Smuzhiyun         return BadMatch;
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun     pScrPriv->lastSetTime = time;
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun     status = RRSetConfigSuccess;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun  sendReply:
1574*4882a593Smuzhiyun     rep = (xRRSetPanningReply) {
1575*4882a593Smuzhiyun         .type = X_Reply,
1576*4882a593Smuzhiyun         .status = status,
1577*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1578*4882a593Smuzhiyun         .length = 0,
1579*4882a593Smuzhiyun         .newTimestamp = pScrPriv->lastSetTime.milliseconds
1580*4882a593Smuzhiyun     };
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun     if (client->swapped) {
1583*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
1584*4882a593Smuzhiyun         swapl(&rep.length);
1585*4882a593Smuzhiyun         swapl(&rep.newTimestamp);
1586*4882a593Smuzhiyun     }
1587*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
1588*4882a593Smuzhiyun     return Success;
1589*4882a593Smuzhiyun }
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun int
ProcRRGetCrtcGammaSize(ClientPtr client)1592*4882a593Smuzhiyun ProcRRGetCrtcGammaSize(ClientPtr client)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun     REQUEST(xRRGetCrtcGammaSizeReq);
1595*4882a593Smuzhiyun     xRRGetCrtcGammaSizeReply reply;
1596*4882a593Smuzhiyun     RRCrtcPtr crtc;
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1599*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun     /* Gamma retrieval failed, any better error? */
1602*4882a593Smuzhiyun     if (!RRCrtcGammaGet(crtc))
1603*4882a593Smuzhiyun         return RRErrorBase + BadRRCrtc;
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun     reply = (xRRGetCrtcGammaSizeReply) {
1606*4882a593Smuzhiyun         .type = X_Reply,
1607*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1608*4882a593Smuzhiyun         .length = 0,
1609*4882a593Smuzhiyun         .size = crtc->gammaSize
1610*4882a593Smuzhiyun     };
1611*4882a593Smuzhiyun     if (client->swapped) {
1612*4882a593Smuzhiyun         swaps(&reply.sequenceNumber);
1613*4882a593Smuzhiyun         swapl(&reply.length);
1614*4882a593Smuzhiyun         swaps(&reply.size);
1615*4882a593Smuzhiyun     }
1616*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
1617*4882a593Smuzhiyun     return Success;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun int
ProcRRGetCrtcGamma(ClientPtr client)1621*4882a593Smuzhiyun ProcRRGetCrtcGamma(ClientPtr client)
1622*4882a593Smuzhiyun {
1623*4882a593Smuzhiyun     REQUEST(xRRGetCrtcGammaReq);
1624*4882a593Smuzhiyun     xRRGetCrtcGammaReply reply;
1625*4882a593Smuzhiyun     RRCrtcPtr crtc;
1626*4882a593Smuzhiyun     unsigned long len;
1627*4882a593Smuzhiyun     char *extra = NULL;
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1630*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun     /* Gamma retrieval failed, any better error? */
1633*4882a593Smuzhiyun     if (!RRCrtcGammaGet(crtc))
1634*4882a593Smuzhiyun         return RRErrorBase + BadRRCrtc;
1635*4882a593Smuzhiyun 
1636*4882a593Smuzhiyun     len = crtc->gammaSize * 3 * 2;
1637*4882a593Smuzhiyun 
1638*4882a593Smuzhiyun     if (crtc->gammaSize) {
1639*4882a593Smuzhiyun         extra = malloc(len);
1640*4882a593Smuzhiyun         if (!extra)
1641*4882a593Smuzhiyun             return BadAlloc;
1642*4882a593Smuzhiyun     }
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun     reply = (xRRGetCrtcGammaReply) {
1645*4882a593Smuzhiyun         .type = X_Reply,
1646*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
1647*4882a593Smuzhiyun         .length = bytes_to_int32(len),
1648*4882a593Smuzhiyun         .size = crtc->gammaSize
1649*4882a593Smuzhiyun     };
1650*4882a593Smuzhiyun     if (client->swapped) {
1651*4882a593Smuzhiyun         swaps(&reply.sequenceNumber);
1652*4882a593Smuzhiyun         swapl(&reply.length);
1653*4882a593Smuzhiyun         swaps(&reply.size);
1654*4882a593Smuzhiyun     }
1655*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
1656*4882a593Smuzhiyun     if (crtc->gammaSize) {
1657*4882a593Smuzhiyun         memcpy(extra, crtc->gammaRed, len);
1658*4882a593Smuzhiyun         client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
1659*4882a593Smuzhiyun         WriteSwappedDataToClient(client, len, extra);
1660*4882a593Smuzhiyun         free(extra);
1661*4882a593Smuzhiyun     }
1662*4882a593Smuzhiyun     return Success;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun int
ProcRRSetCrtcGamma(ClientPtr client)1666*4882a593Smuzhiyun ProcRRSetCrtcGamma(ClientPtr client)
1667*4882a593Smuzhiyun {
1668*4882a593Smuzhiyun     REQUEST(xRRSetCrtcGammaReq);
1669*4882a593Smuzhiyun     RRCrtcPtr crtc;
1670*4882a593Smuzhiyun     unsigned long len;
1671*4882a593Smuzhiyun     CARD16 *red, *green, *blue;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun     REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1674*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun     if (RRCrtcIsLeased(crtc))
1677*4882a593Smuzhiyun         return BadAccess;
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun     len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
1680*4882a593Smuzhiyun     if (len < (stuff->size * 3 + 1) >> 1)
1681*4882a593Smuzhiyun         return BadLength;
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun     if (stuff->size != crtc->gammaSize)
1684*4882a593Smuzhiyun         return BadMatch;
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun     red = (CARD16 *) (stuff + 1);
1687*4882a593Smuzhiyun     green = red + crtc->gammaSize;
1688*4882a593Smuzhiyun     blue = green + crtc->gammaSize;
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun     RRCrtcGammaSet(crtc, red, green, blue);
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun     return Success;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun /* Version 1.3 additions */
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun int
ProcRRSetCrtcTransform(ClientPtr client)1698*4882a593Smuzhiyun ProcRRSetCrtcTransform(ClientPtr client)
1699*4882a593Smuzhiyun {
1700*4882a593Smuzhiyun     REQUEST(xRRSetCrtcTransformReq);
1701*4882a593Smuzhiyun     RRCrtcPtr crtc;
1702*4882a593Smuzhiyun     PictTransform transform;
1703*4882a593Smuzhiyun     struct pixman_f_transform f_transform, f_inverse;
1704*4882a593Smuzhiyun     char *filter;
1705*4882a593Smuzhiyun     int nbytes;
1706*4882a593Smuzhiyun     xFixed *params;
1707*4882a593Smuzhiyun     int nparams;
1708*4882a593Smuzhiyun 
1709*4882a593Smuzhiyun     REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1710*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun     if (RRCrtcIsLeased(crtc))
1713*4882a593Smuzhiyun         return BadAccess;
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun     PictTransform_from_xRenderTransform(&transform, &stuff->transform);
1716*4882a593Smuzhiyun     pixman_f_transform_from_pixman_transform(&f_transform, &transform);
1717*4882a593Smuzhiyun     if (!pixman_f_transform_invert(&f_inverse, &f_transform))
1718*4882a593Smuzhiyun         return BadMatch;
1719*4882a593Smuzhiyun 
1720*4882a593Smuzhiyun     filter = (char *) (stuff + 1);
1721*4882a593Smuzhiyun     nbytes = stuff->nbytesFilter;
1722*4882a593Smuzhiyun     params = (xFixed *) (filter + pad_to_int32(nbytes));
1723*4882a593Smuzhiyun     nparams = ((xFixed *) stuff + client->req_len) - params;
1724*4882a593Smuzhiyun     if (nparams < 0)
1725*4882a593Smuzhiyun         return BadLength;
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun     return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
1728*4882a593Smuzhiyun                               filter, nbytes, params, nparams);
1729*4882a593Smuzhiyun }
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun #define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun static int
transform_filter_length(RRTransformPtr transform)1734*4882a593Smuzhiyun transform_filter_length(RRTransformPtr transform)
1735*4882a593Smuzhiyun {
1736*4882a593Smuzhiyun     int nbytes, nparams;
1737*4882a593Smuzhiyun 
1738*4882a593Smuzhiyun     if (transform->filter == NULL)
1739*4882a593Smuzhiyun         return 0;
1740*4882a593Smuzhiyun     nbytes = strlen(transform->filter->name);
1741*4882a593Smuzhiyun     nparams = transform->nparams;
1742*4882a593Smuzhiyun     return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun 
1745*4882a593Smuzhiyun static int
transform_filter_encode(ClientPtr client,char * output,CARD16 * nbytesFilter,CARD16 * nparamsFilter,RRTransformPtr transform)1746*4882a593Smuzhiyun transform_filter_encode(ClientPtr client, char *output,
1747*4882a593Smuzhiyun                         CARD16 *nbytesFilter,
1748*4882a593Smuzhiyun                         CARD16 *nparamsFilter, RRTransformPtr transform)
1749*4882a593Smuzhiyun {
1750*4882a593Smuzhiyun     int nbytes, nparams;
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun     if (transform->filter == NULL) {
1753*4882a593Smuzhiyun         *nbytesFilter = 0;
1754*4882a593Smuzhiyun         *nparamsFilter = 0;
1755*4882a593Smuzhiyun         return 0;
1756*4882a593Smuzhiyun     }
1757*4882a593Smuzhiyun     nbytes = strlen(transform->filter->name);
1758*4882a593Smuzhiyun     nparams = transform->nparams;
1759*4882a593Smuzhiyun     *nbytesFilter = nbytes;
1760*4882a593Smuzhiyun     *nparamsFilter = nparams;
1761*4882a593Smuzhiyun     memcpy(output, transform->filter->name, nbytes);
1762*4882a593Smuzhiyun     while ((nbytes & 3) != 0)
1763*4882a593Smuzhiyun         output[nbytes++] = 0;
1764*4882a593Smuzhiyun     memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
1765*4882a593Smuzhiyun     if (client->swapped) {
1766*4882a593Smuzhiyun         swaps(nbytesFilter);
1767*4882a593Smuzhiyun         swaps(nparamsFilter);
1768*4882a593Smuzhiyun         SwapLongs((CARD32 *) (output + nbytes), nparams);
1769*4882a593Smuzhiyun     }
1770*4882a593Smuzhiyun     nbytes += nparams * sizeof(xFixed);
1771*4882a593Smuzhiyun     return nbytes;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun static void
transform_encode(ClientPtr client,xRenderTransform * wire,PictTransform * pict)1775*4882a593Smuzhiyun transform_encode(ClientPtr client, xRenderTransform * wire,
1776*4882a593Smuzhiyun                  PictTransform * pict)
1777*4882a593Smuzhiyun {
1778*4882a593Smuzhiyun     xRenderTransform_from_PictTransform(wire, pict);
1779*4882a593Smuzhiyun     if (client->swapped)
1780*4882a593Smuzhiyun         SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1781*4882a593Smuzhiyun }
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun int
ProcRRGetCrtcTransform(ClientPtr client)1784*4882a593Smuzhiyun ProcRRGetCrtcTransform(ClientPtr client)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun     REQUEST(xRRGetCrtcTransformReq);
1787*4882a593Smuzhiyun     xRRGetCrtcTransformReply *reply;
1788*4882a593Smuzhiyun     RRCrtcPtr crtc;
1789*4882a593Smuzhiyun     int nextra;
1790*4882a593Smuzhiyun     RRTransformPtr current, pending;
1791*4882a593Smuzhiyun     char *extra;
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
1794*4882a593Smuzhiyun     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1795*4882a593Smuzhiyun 
1796*4882a593Smuzhiyun     pending = &crtc->client_pending_transform;
1797*4882a593Smuzhiyun     current = &crtc->client_current_transform;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun     nextra = (transform_filter_length(pending) +
1800*4882a593Smuzhiyun               transform_filter_length(current));
1801*4882a593Smuzhiyun 
1802*4882a593Smuzhiyun     reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
1803*4882a593Smuzhiyun     if (!reply)
1804*4882a593Smuzhiyun         return BadAlloc;
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun     extra = (char *) (reply + 1);
1807*4882a593Smuzhiyun     reply->type = X_Reply;
1808*4882a593Smuzhiyun     reply->sequenceNumber = client->sequence;
1809*4882a593Smuzhiyun     reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun     reply->hasTransforms = crtc->transforms;
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun     transform_encode(client, &reply->pendingTransform, &pending->transform);
1814*4882a593Smuzhiyun     extra += transform_filter_encode(client, extra,
1815*4882a593Smuzhiyun                                      &reply->pendingNbytesFilter,
1816*4882a593Smuzhiyun                                      &reply->pendingNparamsFilter, pending);
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun     transform_encode(client, &reply->currentTransform, &current->transform);
1819*4882a593Smuzhiyun     extra += transform_filter_encode(client, extra,
1820*4882a593Smuzhiyun                                      &reply->currentNbytesFilter,
1821*4882a593Smuzhiyun                                      &reply->currentNparamsFilter, current);
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun     if (client->swapped) {
1824*4882a593Smuzhiyun         swaps(&reply->sequenceNumber);
1825*4882a593Smuzhiyun         swapl(&reply->length);
1826*4882a593Smuzhiyun     }
1827*4882a593Smuzhiyun     WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
1828*4882a593Smuzhiyun     free(reply);
1829*4882a593Smuzhiyun     return Success;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun static Bool
check_all_screen_crtcs(ScreenPtr pScreen,int * x,int * y)1833*4882a593Smuzhiyun check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
1834*4882a593Smuzhiyun {
1835*4882a593Smuzhiyun     rrScrPriv(pScreen);
1836*4882a593Smuzhiyun     int i;
1837*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1838*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun         int left, right, top, bottom;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun         if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1843*4882a593Smuzhiyun 	    continue;
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun         if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
1846*4882a593Smuzhiyun             return TRUE;
1847*4882a593Smuzhiyun     }
1848*4882a593Smuzhiyun     return FALSE;
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun static Bool
constrain_all_screen_crtcs(DeviceIntPtr pDev,ScreenPtr pScreen,int * x,int * y)1852*4882a593Smuzhiyun constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun     rrScrPriv(pScreen);
1855*4882a593Smuzhiyun     int i;
1856*4882a593Smuzhiyun 
1857*4882a593Smuzhiyun     /* if we're trying to escape, clamp to the CRTC we're coming from */
1858*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1859*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1860*4882a593Smuzhiyun         int nx, ny;
1861*4882a593Smuzhiyun         int left, right, top, bottom;
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun         if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1864*4882a593Smuzhiyun 	    continue;
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun         miPointerGetPosition(pDev, &nx, &ny);
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun         if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
1869*4882a593Smuzhiyun             if (*x < left)
1870*4882a593Smuzhiyun                 *x = left;
1871*4882a593Smuzhiyun             if (*x >= right)
1872*4882a593Smuzhiyun                 *x = right - 1;
1873*4882a593Smuzhiyun             if (*y < top)
1874*4882a593Smuzhiyun                 *y = top;
1875*4882a593Smuzhiyun             if (*y >= bottom)
1876*4882a593Smuzhiyun                 *y = bottom - 1;
1877*4882a593Smuzhiyun 
1878*4882a593Smuzhiyun             return TRUE;
1879*4882a593Smuzhiyun         }
1880*4882a593Smuzhiyun     }
1881*4882a593Smuzhiyun     return FALSE;
1882*4882a593Smuzhiyun }
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun void
RRConstrainCursorHarder(DeviceIntPtr pDev,ScreenPtr pScreen,int mode,int * x,int * y)1885*4882a593Smuzhiyun RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
1886*4882a593Smuzhiyun                         int *y)
1887*4882a593Smuzhiyun {
1888*4882a593Smuzhiyun     rrScrPriv(pScreen);
1889*4882a593Smuzhiyun     Bool ret;
1890*4882a593Smuzhiyun     ScreenPtr slave;
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun     /* intentional dead space -> let it float */
1893*4882a593Smuzhiyun     if (pScrPriv->discontiguous)
1894*4882a593Smuzhiyun         return;
1895*4882a593Smuzhiyun 
1896*4882a593Smuzhiyun     /* if we're moving inside a crtc, we're fine */
1897*4882a593Smuzhiyun     ret = check_all_screen_crtcs(pScreen, x, y);
1898*4882a593Smuzhiyun     if (ret == TRUE)
1899*4882a593Smuzhiyun         return;
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun     xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1902*4882a593Smuzhiyun         if (!slave->is_output_slave)
1903*4882a593Smuzhiyun             continue;
1904*4882a593Smuzhiyun 
1905*4882a593Smuzhiyun         ret = check_all_screen_crtcs(slave, x, y);
1906*4882a593Smuzhiyun         if (ret == TRUE)
1907*4882a593Smuzhiyun             return;
1908*4882a593Smuzhiyun     }
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun     /* if we're trying to escape, clamp to the CRTC we're coming from */
1911*4882a593Smuzhiyun     ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
1912*4882a593Smuzhiyun     if (ret == TRUE)
1913*4882a593Smuzhiyun         return;
1914*4882a593Smuzhiyun 
1915*4882a593Smuzhiyun     xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1916*4882a593Smuzhiyun         if (!slave->is_output_slave)
1917*4882a593Smuzhiyun             continue;
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun         ret = constrain_all_screen_crtcs(pDev, slave, x, y);
1920*4882a593Smuzhiyun         if (ret == TRUE)
1921*4882a593Smuzhiyun             return;
1922*4882a593Smuzhiyun     }
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun Bool
RRReplaceScanoutPixmap(DrawablePtr pDrawable,PixmapPtr pPixmap,Bool enable)1926*4882a593Smuzhiyun RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun     rrScrPriv(pDrawable->pScreen);
1929*4882a593Smuzhiyun     Bool ret = TRUE;
1930*4882a593Smuzhiyun     PixmapPtr *saved_scanout_pixmap;
1931*4882a593Smuzhiyun     int i;
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun     saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
1934*4882a593Smuzhiyun     if (saved_scanout_pixmap == NULL)
1935*4882a593Smuzhiyun         return FALSE;
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1938*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1939*4882a593Smuzhiyun         Bool size_fits;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun         saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1942*4882a593Smuzhiyun 
1943*4882a593Smuzhiyun         if (!crtc->mode && enable)
1944*4882a593Smuzhiyun             continue;
1945*4882a593Smuzhiyun         if (!crtc->scanout_pixmap && !enable)
1946*4882a593Smuzhiyun             continue;
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun         /* not supported with double buffering, needs ABI change for 2 ppix */
1949*4882a593Smuzhiyun         if (crtc->scanout_pixmap_back) {
1950*4882a593Smuzhiyun             ret = FALSE;
1951*4882a593Smuzhiyun             continue;
1952*4882a593Smuzhiyun         }
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun         size_fits = (crtc->mode &&
1955*4882a593Smuzhiyun                      crtc->x == pDrawable->x &&
1956*4882a593Smuzhiyun                      crtc->y == pDrawable->y &&
1957*4882a593Smuzhiyun                      crtc->mode->mode.width == pDrawable->width &&
1958*4882a593Smuzhiyun                      crtc->mode->mode.height == pDrawable->height);
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun         /* is the pixmap already set? */
1961*4882a593Smuzhiyun         if (crtc->scanout_pixmap == pPixmap) {
1962*4882a593Smuzhiyun             /* if its a disable then don't care about size */
1963*4882a593Smuzhiyun             if (enable == FALSE) {
1964*4882a593Smuzhiyun                 /* set scanout to NULL */
1965*4882a593Smuzhiyun                 crtc->scanout_pixmap = NULL;
1966*4882a593Smuzhiyun             }
1967*4882a593Smuzhiyun             else if (!size_fits) {
1968*4882a593Smuzhiyun                 /* if the size no longer fits then drop off */
1969*4882a593Smuzhiyun                 crtc->scanout_pixmap = NULL;
1970*4882a593Smuzhiyun                 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun                 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
1973*4882a593Smuzhiyun                                         crtc->rotation, crtc->numOutputs, crtc->outputs);
1974*4882a593Smuzhiyun                 saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1975*4882a593Smuzhiyun                 ret = FALSE;
1976*4882a593Smuzhiyun             }
1977*4882a593Smuzhiyun             else {
1978*4882a593Smuzhiyun                 /* if the size fits then we are already setup */
1979*4882a593Smuzhiyun             }
1980*4882a593Smuzhiyun         }
1981*4882a593Smuzhiyun         else {
1982*4882a593Smuzhiyun             if (!size_fits)
1983*4882a593Smuzhiyun                 ret = FALSE;
1984*4882a593Smuzhiyun             else if (enable)
1985*4882a593Smuzhiyun                 crtc->scanout_pixmap = pPixmap;
1986*4882a593Smuzhiyun             else
1987*4882a593Smuzhiyun                 /* reject an attempt to disable someone else's scanout_pixmap */
1988*4882a593Smuzhiyun                 ret = FALSE;
1989*4882a593Smuzhiyun         }
1990*4882a593Smuzhiyun     }
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1993*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun         if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
1996*4882a593Smuzhiyun             continue;
1997*4882a593Smuzhiyun 
1998*4882a593Smuzhiyun         if (ret) {
1999*4882a593Smuzhiyun             pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun             (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
2002*4882a593Smuzhiyun                                     crtc->rotation, crtc->numOutputs, crtc->outputs);
2003*4882a593Smuzhiyun         }
2004*4882a593Smuzhiyun         else
2005*4882a593Smuzhiyun             crtc->scanout_pixmap = saved_scanout_pixmap[i];
2006*4882a593Smuzhiyun     }
2007*4882a593Smuzhiyun     free(saved_scanout_pixmap);
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun     return ret;
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun Bool
RRHasScanoutPixmap(ScreenPtr pScreen)2013*4882a593Smuzhiyun RRHasScanoutPixmap(ScreenPtr pScreen)
2014*4882a593Smuzhiyun {
2015*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
2016*4882a593Smuzhiyun     int i;
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun     /* Bail out if RandR wasn't initialized. */
2019*4882a593Smuzhiyun     if (!dixPrivateKeyRegistered(rrPrivKey))
2020*4882a593Smuzhiyun         return FALSE;
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
2023*4882a593Smuzhiyun 
2024*4882a593Smuzhiyun     if (!pScreen->is_output_slave)
2025*4882a593Smuzhiyun         return FALSE;
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun     for (i = 0; i < pScrPriv->numCrtcs; i++) {
2028*4882a593Smuzhiyun         RRCrtcPtr crtc = pScrPriv->crtcs[i];
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun         if (crtc->scanout_pixmap)
2031*4882a593Smuzhiyun             return TRUE;
2032*4882a593Smuzhiyun     }
2033*4882a593Smuzhiyun 
2034*4882a593Smuzhiyun     return FALSE;
2035*4882a593Smuzhiyun }
2036