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, ¤t->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