xref: /OK3568_Linux_fs/external/xserver/randr/rrcrtc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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;
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 
963 /*
964  * Notify the extension that the Crtc gamma has been changed
965  * The driver calls this whenever it has changed the gamma values
966  * in the RRCrtcRec
967  */
968 
969 Bool
RRCrtcGammaNotify(RRCrtcPtr crtc)970 RRCrtcGammaNotify(RRCrtcPtr crtc)
971 {
972     return TRUE;                /* not much going on here */
973 }
974 
975 static void
RRModeGetScanoutSize(RRModePtr mode,PictTransformPtr transform,int * width,int * height)976 RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
977                      int *width, int *height)
978 {
979     BoxRec box;
980 
981     if (mode == NULL) {
982         *width = 0;
983         *height = 0;
984         return;
985     }
986 
987     box.x1 = 0;
988     box.y1 = 0;
989     box.x2 = mode->mode.width;
990     box.y2 = mode->mode.height;
991 
992     pixman_transform_bounds(transform, &box);
993     *width = box.x2 - box.x1;
994     *height = box.y2 - box.y1;
995 }
996 
997 /**
998  * Returns the width/height that the crtc scans out from the framebuffer
999  */
1000 void
RRCrtcGetScanoutSize(RRCrtcPtr crtc,int * width,int * height)1001 RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
1002 {
1003     RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
1004 }
1005 
1006 /*
1007  * Set the size of the gamma table at server startup time
1008  */
1009 
1010 Bool
RRCrtcGammaSetSize(RRCrtcPtr crtc,int size)1011 RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
1012 {
1013     CARD16 *gamma;
1014 
1015     if (size == crtc->gammaSize)
1016         return TRUE;
1017     if (size) {
1018         gamma = xallocarray(size, 3 * sizeof(CARD16));
1019         if (!gamma)
1020             return FALSE;
1021     }
1022     else
1023         gamma = NULL;
1024     free(crtc->gammaRed);
1025     crtc->gammaRed = gamma;
1026     crtc->gammaGreen = gamma + size;
1027     crtc->gammaBlue = gamma + size * 2;
1028     crtc->gammaSize = size;
1029     return TRUE;
1030 }
1031 
1032 /*
1033  * Set the pending CRTC transformation
1034  */
1035 
1036 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 RRCrtcTransformSet(RRCrtcPtr crtc,
1038                    PictTransformPtr transform,
1039                    struct pixman_f_transform *f_transform,
1040                    struct pixman_f_transform *f_inverse,
1041                    char *filter_name,
1042                    int filter_len, xFixed * params, int nparams)
1043 {
1044     PictFilterPtr filter = NULL;
1045     int width = 0, height = 0;
1046 
1047     if (!crtc->transforms)
1048         return BadValue;
1049 
1050     if (filter_len) {
1051         filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
1052         if (!filter)
1053             return BadName;
1054         if (filter->ValidateParams) {
1055             if (!filter->ValidateParams(crtc->pScreen, filter->id,
1056                                         params, nparams, &width, &height))
1057                 return BadMatch;
1058         }
1059         else {
1060             width = filter->width;
1061             height = filter->height;
1062         }
1063     }
1064     else {
1065         if (nparams)
1066             return BadMatch;
1067     }
1068     if (!RRTransformSetFilter(&crtc->client_pending_transform,
1069                               filter, params, nparams, width, height))
1070         return BadAlloc;
1071 
1072     crtc->client_pending_transform.transform = *transform;
1073     crtc->client_pending_transform.f_transform = *f_transform;
1074     crtc->client_pending_transform.f_inverse = *f_inverse;
1075     return Success;
1076 }
1077 
1078 /*
1079  * Initialize crtc type
1080  */
1081 Bool
RRCrtcInit(void)1082 RRCrtcInit(void)
1083 {
1084     RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
1085     if (!RRCrtcType)
1086         return FALSE;
1087 
1088     return TRUE;
1089 }
1090 
1091 /*
1092  * Initialize crtc type error value
1093  */
1094 void
RRCrtcInitErrorValue(void)1095 RRCrtcInitErrorValue(void)
1096 {
1097     SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
1098 }
1099 
1100 int
ProcRRGetCrtcInfo(ClientPtr client)1101 ProcRRGetCrtcInfo(ClientPtr client)
1102 {
1103     REQUEST(xRRGetCrtcInfoReq);
1104     xRRGetCrtcInfoReply rep;
1105     RRCrtcPtr crtc;
1106     CARD8 *extra = NULL;
1107     unsigned long extraLen;
1108     ScreenPtr pScreen;
1109     rrScrPrivPtr pScrPriv;
1110     RRModePtr mode;
1111     RROutput *outputs;
1112     RROutput *possible;
1113     int i, j, k;
1114     int width, height;
1115     BoxRec panned_area;
1116     Bool leased;
1117 
1118     REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
1119     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1120 
1121     leased = RRCrtcIsLeased(crtc);
1122 
1123     /* All crtcs must be associated with screens before client
1124      * requests are processed
1125      */
1126     pScreen = crtc->pScreen;
1127     pScrPriv = rrGetScrPriv(pScreen);
1128 
1129     mode = crtc->mode;
1130 
1131     rep = (xRRGetCrtcInfoReply) {
1132         .type = X_Reply,
1133         .status = RRSetConfigSuccess,
1134         .sequenceNumber = client->sequence,
1135         .length = 0,
1136         .timestamp = pScrPriv->lastSetTime.milliseconds
1137     };
1138     if (leased) {
1139         rep.x = rep.y = rep.width = rep.height = 0;
1140         rep.mode = 0;
1141         rep.rotation = RR_Rotate_0;
1142         rep.rotations = RR_Rotate_0;
1143         rep.nOutput = 0;
1144         rep.nPossibleOutput = 0;
1145         rep.length = 0;
1146         extraLen = 0;
1147     } else {
1148         if (pScrPriv->rrGetPanning &&
1149             pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
1150             (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
1151         {
1152             rep.x = panned_area.x1;
1153             rep.y = panned_area.y1;
1154             rep.width = panned_area.x2 - panned_area.x1;
1155             rep.height = panned_area.y2 - panned_area.y1;
1156         }
1157         else {
1158             RRCrtcGetScanoutSize(crtc, &width, &height);
1159             rep.x = crtc->x;
1160             rep.y = crtc->y;
1161             rep.width = width;
1162             rep.height = height;
1163         }
1164         rep.mode = mode ? mode->mode.id : 0;
1165         rep.rotation = crtc->rotation;
1166         rep.rotations = crtc->rotations;
1167         rep.nOutput = crtc->numOutputs;
1168         k = 0;
1169         for (i = 0; i < pScrPriv->numOutputs; i++) {
1170             if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1171                 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1172                     if (pScrPriv->outputs[i]->crtcs[j] == crtc)
1173                         k++;
1174             }
1175         }
1176 
1177         rep.nPossibleOutput = k;
1178 
1179         rep.length = rep.nOutput + rep.nPossibleOutput;
1180 
1181         extraLen = rep.length << 2;
1182         if (extraLen) {
1183             extra = malloc(extraLen);
1184             if (!extra)
1185                 return BadAlloc;
1186         }
1187 
1188         outputs = (RROutput *) extra;
1189         possible = (RROutput *) (outputs + rep.nOutput);
1190 
1191         for (i = 0; i < crtc->numOutputs; i++) {
1192             outputs[i] = crtc->outputs[i]->id;
1193             if (client->swapped)
1194                 swapl(&outputs[i]);
1195         }
1196         k = 0;
1197         for (i = 0; i < pScrPriv->numOutputs; i++) {
1198             if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1199                 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1200                     if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
1201                         possible[k] = pScrPriv->outputs[i]->id;
1202                         if (client->swapped)
1203                             swapl(&possible[k]);
1204                         k++;
1205                     }
1206             }
1207         }
1208     }
1209 
1210     if (client->swapped) {
1211         swaps(&rep.sequenceNumber);
1212         swapl(&rep.length);
1213         swapl(&rep.timestamp);
1214         swaps(&rep.x);
1215         swaps(&rep.y);
1216         swaps(&rep.width);
1217         swaps(&rep.height);
1218         swapl(&rep.mode);
1219         swaps(&rep.rotation);
1220         swaps(&rep.rotations);
1221         swaps(&rep.nOutput);
1222         swaps(&rep.nPossibleOutput);
1223     }
1224     WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
1225     if (extraLen) {
1226         WriteToClient(client, extraLen, extra);
1227         free(extra);
1228     }
1229 
1230     return Success;
1231 }
1232 
1233 int
ProcRRSetCrtcConfig(ClientPtr client)1234 ProcRRSetCrtcConfig(ClientPtr client)
1235 {
1236     REQUEST(xRRSetCrtcConfigReq);
1237     xRRSetCrtcConfigReply rep;
1238     ScreenPtr pScreen;
1239     rrScrPrivPtr pScrPriv;
1240     RRCrtcPtr crtc;
1241     RRModePtr mode;
1242     int numOutputs;
1243     RROutputPtr *outputs = NULL;
1244     RROutput *outputIds;
1245     TimeStamp time;
1246     Rotation rotation;
1247     int ret, i, j;
1248     CARD8 status;
1249 
1250     REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
1251     numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
1252 
1253     VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
1254 
1255     if (RRCrtcIsLeased(crtc))
1256         return BadAccess;
1257 
1258     if (stuff->mode == None) {
1259         mode = NULL;
1260         if (numOutputs > 0)
1261             return BadMatch;
1262     }
1263     else {
1264         VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
1265         if (numOutputs == 0)
1266             return BadMatch;
1267     }
1268     if (numOutputs) {
1269         outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
1270         if (!outputs)
1271             return BadAlloc;
1272     }
1273     else
1274         outputs = NULL;
1275 
1276     outputIds = (RROutput *) (stuff + 1);
1277     for (i = 0; i < numOutputs; i++) {
1278         ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
1279                                      RROutputType, client, DixSetAttrAccess);
1280         if (ret != Success) {
1281             free(outputs);
1282             return ret;
1283         }
1284 
1285         if (RROutputIsLeased(outputs[i])) {
1286             free(outputs);
1287             return BadAccess;
1288         }
1289 
1290         /* validate crtc for this output */
1291         for (j = 0; j < outputs[i]->numCrtcs; j++)
1292             if (outputs[i]->crtcs[j] == crtc)
1293                 break;
1294         if (j == outputs[i]->numCrtcs) {
1295             free(outputs);
1296             return BadMatch;
1297         }
1298         /* validate mode for this output */
1299         for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
1300             RRModePtr m = (j < outputs[i]->numModes ?
1301                            outputs[i]->modes[j] :
1302                            outputs[i]->userModes[j - outputs[i]->numModes]);
1303             if (m == mode)
1304                 break;
1305         }
1306         if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
1307             free(outputs);
1308             return BadMatch;
1309         }
1310     }
1311     /* validate clones */
1312     for (i = 0; i < numOutputs; i++) {
1313         for (j = 0; j < numOutputs; j++) {
1314             int k;
1315 
1316             if (i == j)
1317                 continue;
1318             for (k = 0; k < outputs[i]->numClones; k++) {
1319                 if (outputs[i]->clones[k] == outputs[j])
1320                     break;
1321             }
1322             if (k == outputs[i]->numClones) {
1323                 free(outputs);
1324                 return BadMatch;
1325             }
1326         }
1327     }
1328 
1329     pScreen = crtc->pScreen;
1330     pScrPriv = rrGetScrPriv(pScreen);
1331 
1332     time = ClientTimeToServerTime(stuff->timestamp);
1333 
1334     if (!pScrPriv) {
1335         time = currentTime;
1336         status = RRSetConfigFailed;
1337         goto sendReply;
1338     }
1339 
1340     /*
1341      * Validate requested rotation
1342      */
1343     rotation = (Rotation) stuff->rotation;
1344 
1345     /* test the rotation bits only! */
1346     switch (rotation & 0xf) {
1347     case RR_Rotate_0:
1348     case RR_Rotate_90:
1349     case RR_Rotate_180:
1350     case RR_Rotate_270:
1351         break;
1352     default:
1353         /*
1354          * Invalid rotation
1355          */
1356         client->errorValue = stuff->rotation;
1357         free(outputs);
1358         return BadValue;
1359     }
1360 
1361     if (mode) {
1362         if ((~crtc->rotations) & rotation) {
1363             /*
1364              * requested rotation or reflection not supported by screen
1365              */
1366             client->errorValue = stuff->rotation;
1367             free(outputs);
1368             return BadMatch;
1369         }
1370 
1371 #ifdef RANDR_12_INTERFACE
1372         /*
1373          * Check screen size bounds if the DDX provides a 1.2 interface
1374          * for setting screen size. Else, assume the CrtcSet sets
1375          * the size along with the mode. If the driver supports transforms,
1376          * then it must allow crtcs to display a subset of the screen, so
1377          * only do this check for drivers without transform support.
1378          */
1379         if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
1380             int source_width;
1381             int source_height;
1382             PictTransform transform;
1383             struct pixman_f_transform f_transform, f_inverse;
1384             int width, height;
1385 
1386             if (pScreen->isGPU) {
1387                 width = pScreen->current_master->width;
1388                 height = pScreen->current_master->height;
1389             }
1390             else {
1391                 width = pScreen->width;
1392                 height = pScreen->height;
1393             }
1394 
1395             RRTransformCompute(stuff->x, stuff->y,
1396                                mode->mode.width, mode->mode.height,
1397                                rotation,
1398                                &crtc->client_pending_transform,
1399                                &transform, &f_transform, &f_inverse);
1400 
1401             RRModeGetScanoutSize(mode, &transform, &source_width,
1402                                  &source_height);
1403             if (stuff->x + source_width > width) {
1404                 client->errorValue = stuff->x;
1405                 free(outputs);
1406                 return BadValue;
1407             }
1408 
1409             if (stuff->y + source_height > height) {
1410                 client->errorValue = stuff->y;
1411                 free(outputs);
1412                 return BadValue;
1413             }
1414         }
1415 #endif
1416     }
1417 
1418     if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
1419                    rotation, numOutputs, outputs)) {
1420         status = RRSetConfigFailed;
1421         goto sendReply;
1422     }
1423     status = RRSetConfigSuccess;
1424     pScrPriv->lastSetTime = time;
1425 
1426  sendReply:
1427     free(outputs);
1428 
1429     rep = (xRRSetCrtcConfigReply) {
1430         .type = X_Reply,
1431         .status = status,
1432         .sequenceNumber = client->sequence,
1433         .length = 0,
1434         .newTimestamp = pScrPriv->lastSetTime.milliseconds
1435     };
1436 
1437     if (client->swapped) {
1438         swaps(&rep.sequenceNumber);
1439         swapl(&rep.length);
1440         swapl(&rep.newTimestamp);
1441     }
1442     WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
1443 
1444     return Success;
1445 }
1446 
1447 int
ProcRRGetPanning(ClientPtr client)1448 ProcRRGetPanning(ClientPtr client)
1449 {
1450     REQUEST(xRRGetPanningReq);
1451     xRRGetPanningReply rep;
1452     RRCrtcPtr crtc;
1453     ScreenPtr pScreen;
1454     rrScrPrivPtr pScrPriv;
1455     BoxRec total;
1456     BoxRec tracking;
1457     INT16 border[4];
1458 
1459     REQUEST_SIZE_MATCH(xRRGetPanningReq);
1460     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1461 
1462     /* All crtcs must be associated with screens before client
1463      * requests are processed
1464      */
1465     pScreen = crtc->pScreen;
1466     pScrPriv = rrGetScrPriv(pScreen);
1467 
1468     if (!pScrPriv)
1469         return RRErrorBase + BadRRCrtc;
1470 
1471     rep = (xRRGetPanningReply) {
1472         .type = X_Reply,
1473         .status = RRSetConfigSuccess,
1474         .sequenceNumber = client->sequence,
1475         .length = 1,
1476         .timestamp = pScrPriv->lastSetTime.milliseconds
1477     };
1478 
1479     if (pScrPriv->rrGetPanning &&
1480         pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
1481         rep.left = total.x1;
1482         rep.top = total.y1;
1483         rep.width = total.x2 - total.x1;
1484         rep.height = total.y2 - total.y1;
1485         rep.track_left = tracking.x1;
1486         rep.track_top = tracking.y1;
1487         rep.track_width = tracking.x2 - tracking.x1;
1488         rep.track_height = tracking.y2 - tracking.y1;
1489         rep.border_left = border[0];
1490         rep.border_top = border[1];
1491         rep.border_right = border[2];
1492         rep.border_bottom = border[3];
1493     }
1494 
1495     if (client->swapped) {
1496         swaps(&rep.sequenceNumber);
1497         swapl(&rep.length);
1498         swapl(&rep.timestamp);
1499         swaps(&rep.left);
1500         swaps(&rep.top);
1501         swaps(&rep.width);
1502         swaps(&rep.height);
1503         swaps(&rep.track_left);
1504         swaps(&rep.track_top);
1505         swaps(&rep.track_width);
1506         swaps(&rep.track_height);
1507         swaps(&rep.border_left);
1508         swaps(&rep.border_top);
1509         swaps(&rep.border_right);
1510         swaps(&rep.border_bottom);
1511     }
1512     WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
1513     return Success;
1514 }
1515 
1516 int
ProcRRSetPanning(ClientPtr client)1517 ProcRRSetPanning(ClientPtr client)
1518 {
1519     REQUEST(xRRSetPanningReq);
1520     xRRSetPanningReply rep;
1521     RRCrtcPtr crtc;
1522     ScreenPtr pScreen;
1523     rrScrPrivPtr pScrPriv;
1524     TimeStamp time;
1525     BoxRec total;
1526     BoxRec tracking;
1527     INT16 border[4];
1528     CARD8 status;
1529 
1530     REQUEST_SIZE_MATCH(xRRSetPanningReq);
1531     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1532 
1533     if (RRCrtcIsLeased(crtc))
1534         return BadAccess;
1535 
1536     /* All crtcs must be associated with screens before client
1537      * requests are processed
1538      */
1539     pScreen = crtc->pScreen;
1540     pScrPriv = rrGetScrPriv(pScreen);
1541 
1542     if (!pScrPriv) {
1543         time = currentTime;
1544         status = RRSetConfigFailed;
1545         goto sendReply;
1546     }
1547 
1548     time = ClientTimeToServerTime(stuff->timestamp);
1549 
1550     if (!pScrPriv->rrGetPanning)
1551         return RRErrorBase + BadRRCrtc;
1552 
1553     total.x1 = stuff->left;
1554     total.y1 = stuff->top;
1555     total.x2 = total.x1 + stuff->width;
1556     total.y2 = total.y1 + stuff->height;
1557     tracking.x1 = stuff->track_left;
1558     tracking.y1 = stuff->track_top;
1559     tracking.x2 = tracking.x1 + stuff->track_width;
1560     tracking.y2 = tracking.y1 + stuff->track_height;
1561     border[0] = stuff->border_left;
1562     border[1] = stuff->border_top;
1563     border[2] = stuff->border_right;
1564     border[3] = stuff->border_bottom;
1565 
1566     if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
1567         return BadMatch;
1568 
1569     pScrPriv->lastSetTime = time;
1570 
1571     status = RRSetConfigSuccess;
1572 
1573  sendReply:
1574     rep = (xRRSetPanningReply) {
1575         .type = X_Reply,
1576         .status = status,
1577         .sequenceNumber = client->sequence,
1578         .length = 0,
1579         .newTimestamp = pScrPriv->lastSetTime.milliseconds
1580     };
1581 
1582     if (client->swapped) {
1583         swaps(&rep.sequenceNumber);
1584         swapl(&rep.length);
1585         swapl(&rep.newTimestamp);
1586     }
1587     WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
1588     return Success;
1589 }
1590 
1591 int
ProcRRGetCrtcGammaSize(ClientPtr client)1592 ProcRRGetCrtcGammaSize(ClientPtr client)
1593 {
1594     REQUEST(xRRGetCrtcGammaSizeReq);
1595     xRRGetCrtcGammaSizeReply reply;
1596     RRCrtcPtr crtc;
1597 
1598     REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1599     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1600 
1601     /* Gamma retrieval failed, any better error? */
1602     if (!RRCrtcGammaGet(crtc))
1603         return RRErrorBase + BadRRCrtc;
1604 
1605     reply = (xRRGetCrtcGammaSizeReply) {
1606         .type = X_Reply,
1607         .sequenceNumber = client->sequence,
1608         .length = 0,
1609         .size = crtc->gammaSize
1610     };
1611     if (client->swapped) {
1612         swaps(&reply.sequenceNumber);
1613         swapl(&reply.length);
1614         swaps(&reply.size);
1615     }
1616     WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
1617     return Success;
1618 }
1619 
1620 int
ProcRRGetCrtcGamma(ClientPtr client)1621 ProcRRGetCrtcGamma(ClientPtr client)
1622 {
1623     REQUEST(xRRGetCrtcGammaReq);
1624     xRRGetCrtcGammaReply reply;
1625     RRCrtcPtr crtc;
1626     unsigned long len;
1627     char *extra = NULL;
1628 
1629     REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1630     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1631 
1632     /* Gamma retrieval failed, any better error? */
1633     if (!RRCrtcGammaGet(crtc))
1634         return RRErrorBase + BadRRCrtc;
1635 
1636     len = crtc->gammaSize * 3 * 2;
1637 
1638     if (crtc->gammaSize) {
1639         extra = malloc(len);
1640         if (!extra)
1641             return BadAlloc;
1642     }
1643 
1644     reply = (xRRGetCrtcGammaReply) {
1645         .type = X_Reply,
1646         .sequenceNumber = client->sequence,
1647         .length = bytes_to_int32(len),
1648         .size = crtc->gammaSize
1649     };
1650     if (client->swapped) {
1651         swaps(&reply.sequenceNumber);
1652         swapl(&reply.length);
1653         swaps(&reply.size);
1654     }
1655     WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
1656     if (crtc->gammaSize) {
1657         memcpy(extra, crtc->gammaRed, len);
1658         client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
1659         WriteSwappedDataToClient(client, len, extra);
1660         free(extra);
1661     }
1662     return Success;
1663 }
1664 
1665 int
ProcRRSetCrtcGamma(ClientPtr client)1666 ProcRRSetCrtcGamma(ClientPtr client)
1667 {
1668     REQUEST(xRRSetCrtcGammaReq);
1669     RRCrtcPtr crtc;
1670     unsigned long len;
1671     CARD16 *red, *green, *blue;
1672 
1673     REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1674     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1675 
1676     if (RRCrtcIsLeased(crtc))
1677         return BadAccess;
1678 
1679     len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
1680     if (len < (stuff->size * 3 + 1) >> 1)
1681         return BadLength;
1682 
1683     if (stuff->size != crtc->gammaSize)
1684         return BadMatch;
1685 
1686     red = (CARD16 *) (stuff + 1);
1687     green = red + crtc->gammaSize;
1688     blue = green + crtc->gammaSize;
1689 
1690     RRCrtcGammaSet(crtc, red, green, blue);
1691 
1692     return Success;
1693 }
1694 
1695 /* Version 1.3 additions */
1696 
1697 int
ProcRRSetCrtcTransform(ClientPtr client)1698 ProcRRSetCrtcTransform(ClientPtr client)
1699 {
1700     REQUEST(xRRSetCrtcTransformReq);
1701     RRCrtcPtr crtc;
1702     PictTransform transform;
1703     struct pixman_f_transform f_transform, f_inverse;
1704     char *filter;
1705     int nbytes;
1706     xFixed *params;
1707     int nparams;
1708 
1709     REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1710     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1711 
1712     if (RRCrtcIsLeased(crtc))
1713         return BadAccess;
1714 
1715     PictTransform_from_xRenderTransform(&transform, &stuff->transform);
1716     pixman_f_transform_from_pixman_transform(&f_transform, &transform);
1717     if (!pixman_f_transform_invert(&f_inverse, &f_transform))
1718         return BadMatch;
1719 
1720     filter = (char *) (stuff + 1);
1721     nbytes = stuff->nbytesFilter;
1722     params = (xFixed *) (filter + pad_to_int32(nbytes));
1723     nparams = ((xFixed *) stuff + client->req_len) - params;
1724     if (nparams < 0)
1725         return BadLength;
1726 
1727     return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
1728                               filter, nbytes, params, nparams);
1729 }
1730 
1731 #define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1732 
1733 static int
transform_filter_length(RRTransformPtr transform)1734 transform_filter_length(RRTransformPtr transform)
1735 {
1736     int nbytes, nparams;
1737 
1738     if (transform->filter == NULL)
1739         return 0;
1740     nbytes = strlen(transform->filter->name);
1741     nparams = transform->nparams;
1742     return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
1743 }
1744 
1745 static int
transform_filter_encode(ClientPtr client,char * output,CARD16 * nbytesFilter,CARD16 * nparamsFilter,RRTransformPtr transform)1746 transform_filter_encode(ClientPtr client, char *output,
1747                         CARD16 *nbytesFilter,
1748                         CARD16 *nparamsFilter, RRTransformPtr transform)
1749 {
1750     int nbytes, nparams;
1751 
1752     if (transform->filter == NULL) {
1753         *nbytesFilter = 0;
1754         *nparamsFilter = 0;
1755         return 0;
1756     }
1757     nbytes = strlen(transform->filter->name);
1758     nparams = transform->nparams;
1759     *nbytesFilter = nbytes;
1760     *nparamsFilter = nparams;
1761     memcpy(output, transform->filter->name, nbytes);
1762     while ((nbytes & 3) != 0)
1763         output[nbytes++] = 0;
1764     memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
1765     if (client->swapped) {
1766         swaps(nbytesFilter);
1767         swaps(nparamsFilter);
1768         SwapLongs((CARD32 *) (output + nbytes), nparams);
1769     }
1770     nbytes += nparams * sizeof(xFixed);
1771     return nbytes;
1772 }
1773 
1774 static void
transform_encode(ClientPtr client,xRenderTransform * wire,PictTransform * pict)1775 transform_encode(ClientPtr client, xRenderTransform * wire,
1776                  PictTransform * pict)
1777 {
1778     xRenderTransform_from_PictTransform(wire, pict);
1779     if (client->swapped)
1780         SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1781 }
1782 
1783 int
ProcRRGetCrtcTransform(ClientPtr client)1784 ProcRRGetCrtcTransform(ClientPtr client)
1785 {
1786     REQUEST(xRRGetCrtcTransformReq);
1787     xRRGetCrtcTransformReply *reply;
1788     RRCrtcPtr crtc;
1789     int nextra;
1790     RRTransformPtr current, pending;
1791     char *extra;
1792 
1793     REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
1794     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1795 
1796     pending = &crtc->client_pending_transform;
1797     current = &crtc->client_current_transform;
1798 
1799     nextra = (transform_filter_length(pending) +
1800               transform_filter_length(current));
1801 
1802     reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
1803     if (!reply)
1804         return BadAlloc;
1805 
1806     extra = (char *) (reply + 1);
1807     reply->type = X_Reply;
1808     reply->sequenceNumber = client->sequence;
1809     reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1810 
1811     reply->hasTransforms = crtc->transforms;
1812 
1813     transform_encode(client, &reply->pendingTransform, &pending->transform);
1814     extra += transform_filter_encode(client, extra,
1815                                      &reply->pendingNbytesFilter,
1816                                      &reply->pendingNparamsFilter, pending);
1817 
1818     transform_encode(client, &reply->currentTransform, &current->transform);
1819     extra += transform_filter_encode(client, extra,
1820                                      &reply->currentNbytesFilter,
1821                                      &reply->currentNparamsFilter, current);
1822 
1823     if (client->swapped) {
1824         swaps(&reply->sequenceNumber);
1825         swapl(&reply->length);
1826     }
1827     WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
1828     free(reply);
1829     return Success;
1830 }
1831 
1832 static Bool
check_all_screen_crtcs(ScreenPtr pScreen,int * x,int * y)1833 check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
1834 {
1835     rrScrPriv(pScreen);
1836     int i;
1837     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1838         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1839 
1840         int left, right, top, bottom;
1841 
1842         if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1843 	    continue;
1844 
1845         if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
1846             return TRUE;
1847     }
1848     return FALSE;
1849 }
1850 
1851 static Bool
constrain_all_screen_crtcs(DeviceIntPtr pDev,ScreenPtr pScreen,int * x,int * y)1852 constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
1853 {
1854     rrScrPriv(pScreen);
1855     int i;
1856 
1857     /* if we're trying to escape, clamp to the CRTC we're coming from */
1858     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1859         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1860         int nx, ny;
1861         int left, right, top, bottom;
1862 
1863         if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1864 	    continue;
1865 
1866         miPointerGetPosition(pDev, &nx, &ny);
1867 
1868         if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
1869             if (*x < left)
1870                 *x = left;
1871             if (*x >= right)
1872                 *x = right - 1;
1873             if (*y < top)
1874                 *y = top;
1875             if (*y >= bottom)
1876                 *y = bottom - 1;
1877 
1878             return TRUE;
1879         }
1880     }
1881     return FALSE;
1882 }
1883 
1884 void
RRConstrainCursorHarder(DeviceIntPtr pDev,ScreenPtr pScreen,int mode,int * x,int * y)1885 RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
1886                         int *y)
1887 {
1888     rrScrPriv(pScreen);
1889     Bool ret;
1890     ScreenPtr slave;
1891 
1892     /* intentional dead space -> let it float */
1893     if (pScrPriv->discontiguous)
1894         return;
1895 
1896     /* if we're moving inside a crtc, we're fine */
1897     ret = check_all_screen_crtcs(pScreen, x, y);
1898     if (ret == TRUE)
1899         return;
1900 
1901     xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1902         if (!slave->is_output_slave)
1903             continue;
1904 
1905         ret = check_all_screen_crtcs(slave, x, y);
1906         if (ret == TRUE)
1907             return;
1908     }
1909 
1910     /* if we're trying to escape, clamp to the CRTC we're coming from */
1911     ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
1912     if (ret == TRUE)
1913         return;
1914 
1915     xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1916         if (!slave->is_output_slave)
1917             continue;
1918 
1919         ret = constrain_all_screen_crtcs(pDev, slave, x, y);
1920         if (ret == TRUE)
1921             return;
1922     }
1923 }
1924 
1925 Bool
RRReplaceScanoutPixmap(DrawablePtr pDrawable,PixmapPtr pPixmap,Bool enable)1926 RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
1927 {
1928     rrScrPriv(pDrawable->pScreen);
1929     Bool ret = TRUE;
1930     PixmapPtr *saved_scanout_pixmap;
1931     int i;
1932 
1933     saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
1934     if (saved_scanout_pixmap == NULL)
1935         return FALSE;
1936 
1937     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1938         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1939         Bool size_fits;
1940 
1941         saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1942 
1943         if (!crtc->mode && enable)
1944             continue;
1945         if (!crtc->scanout_pixmap && !enable)
1946             continue;
1947 
1948         /* not supported with double buffering, needs ABI change for 2 ppix */
1949         if (crtc->scanout_pixmap_back) {
1950             ret = FALSE;
1951             continue;
1952         }
1953 
1954         size_fits = (crtc->mode &&
1955                      crtc->x == pDrawable->x &&
1956                      crtc->y == pDrawable->y &&
1957                      crtc->mode->mode.width == pDrawable->width &&
1958                      crtc->mode->mode.height == pDrawable->height);
1959 
1960         /* is the pixmap already set? */
1961         if (crtc->scanout_pixmap == pPixmap) {
1962             /* if its a disable then don't care about size */
1963             if (enable == FALSE) {
1964                 /* set scanout to NULL */
1965                 crtc->scanout_pixmap = NULL;
1966             }
1967             else if (!size_fits) {
1968                 /* if the size no longer fits then drop off */
1969                 crtc->scanout_pixmap = NULL;
1970                 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
1971 
1972                 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
1973                                         crtc->rotation, crtc->numOutputs, crtc->outputs);
1974                 saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1975                 ret = FALSE;
1976             }
1977             else {
1978                 /* if the size fits then we are already setup */
1979             }
1980         }
1981         else {
1982             if (!size_fits)
1983                 ret = FALSE;
1984             else if (enable)
1985                 crtc->scanout_pixmap = pPixmap;
1986             else
1987                 /* reject an attempt to disable someone else's scanout_pixmap */
1988                 ret = FALSE;
1989         }
1990     }
1991 
1992     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1993         RRCrtcPtr crtc = pScrPriv->crtcs[i];
1994 
1995         if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
1996             continue;
1997 
1998         if (ret) {
1999             pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
2000 
2001             (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
2002                                     crtc->rotation, crtc->numOutputs, crtc->outputs);
2003         }
2004         else
2005             crtc->scanout_pixmap = saved_scanout_pixmap[i];
2006     }
2007     free(saved_scanout_pixmap);
2008 
2009     return ret;
2010 }
2011 
2012 Bool
RRHasScanoutPixmap(ScreenPtr pScreen)2013 RRHasScanoutPixmap(ScreenPtr pScreen)
2014 {
2015     rrScrPrivPtr pScrPriv;
2016     int i;
2017 
2018     /* Bail out if RandR wasn't initialized. */
2019     if (!dixPrivateKeyRegistered(rrPrivKey))
2020         return FALSE;
2021 
2022     pScrPriv = rrGetScrPriv(pScreen);
2023 
2024     if (!pScreen->is_output_slave)
2025         return FALSE;
2026 
2027     for (i = 0; i < pScrPriv->numCrtcs; i++) {
2028         RRCrtcPtr crtc = pScrPriv->crtcs[i];
2029 
2030         if (crtc->scanout_pixmap)
2031             return TRUE;
2032     }
2033 
2034     return FALSE;
2035 }
2036