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