xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

rrcrtc.c (58264B)


      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    375 rrDestroySharedPixmap(RRCrtcPtr crtc, PixmapPtr pPixmap) {
    376     ScreenPtr primary = crtc->pScreen->current_primary;
    377 
    378     if (primary && pPixmap->primary_pixmap) {
    379         /*
    380          * Unref the pixmap twice: once for the original reference, and once
    381          * for the reference implicitly added by PixmapShareToSecondary.
    382          */
    383         PixmapUnshareSecondaryPixmap(pPixmap);
    384 
    385         primary->DestroyPixmap(pPixmap->primary_pixmap);
    386         primary->DestroyPixmap(pPixmap->primary_pixmap);
    387     }
    388 
    389     crtc->pScreen->DestroyPixmap(pPixmap);
    390 }
    391 
    392 void
    393 RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
    394 {
    395     rrScrPriv(crtc->pScreen);
    396 
    397     if (crtc->scanout_pixmap) {
    398         ScreenPtr primary = crtc->pScreen->current_primary;
    399         DrawablePtr mrootdraw = &primary->root->drawable;
    400 
    401         if (crtc->scanout_pixmap_back) {
    402             pScrPriv->rrDisableSharedPixmapFlipping(crtc);
    403 
    404             if (mrootdraw) {
    405                 primary->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                 primary->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
    430 rrCreateSharedPixmap(RRCrtcPtr crtc, ScreenPtr primary,
    431                      int width, int height, int depth,
    432                      int x, int y, Rotation rotation)
    433 {
    434     PixmapPtr mpix, spix;
    435 
    436     mpix = primary->CreatePixmap(primary, width, height, depth,
    437                                 CREATE_PIXMAP_USAGE_SHARED);
    438     if (!mpix)
    439         return NULL;
    440 
    441     spix = PixmapShareToSecondary(mpix, crtc->pScreen);
    442     if (spix == NULL) {
    443         primary->DestroyPixmap(mpix);
    444         return NULL;
    445     }
    446 
    447     return spix;
    448 }
    449 
    450 static Bool
    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
    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
    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 primary = crtc->pScreen->current_primary;
    506     rrScrPrivPtr pPrimaryScrPriv = rrGetScrPriv(primary);
    507     rrScrPrivPtr pSecondaryScrPriv = rrGetScrPriv(crtc->pScreen);
    508     DrawablePtr mrootdraw = &primary->root->drawable;
    509     int depth = mrootdraw->depth;
    510     PixmapPtr spix_front;
    511 
    512     /* Create a pixmap on the primary screen, then get a shared handle for it.
    513        Create a shared pixmap on the secondary screen using the handle.
    514 
    515        If sync == FALSE --
    516        Set secondary screen to scanout shared linear pixmap.
    517        Set the primary 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 secondary screen using the handle.
    523        Set secondary screen to prepare for scanout and flipping between shared
    524        linear pixmaps.
    525        Set the primary screen to do dirty updates to the shared pixmaps from the
    526        screen pixmap when prompted to by us or the secondary.
    527        Prompt the primary to do a dirty update on the first shared pixmap, then
    528        defer to the secondary.
    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, primary,
    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         pSecondaryScrPriv->rrEnableSharedPixmapFlipping &&
    549         pSecondaryScrPriv->rrDisableSharedPixmapFlipping &&
    550         pPrimaryScrPriv->rrStartFlippingPixmapTracking &&
    551         primary->PresentSharedPixmap &&
    552         primary->StopFlippingPixmapTracking) {
    553 
    554         PixmapPtr spix_back = rrCreateSharedPixmap(crtc, primary,
    555                                                    width, height, depth,
    556                                                    x, y, rotation);
    557         if (spix_back == NULL)
    558             goto fail;
    559 
    560         if (!pSecondaryScrPriv->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 (!pPrimaryScrPriv->rrStartFlippingPixmapTracking(crtc,
    568                                                            mrootdraw,
    569                                                            spix_front,
    570                                                            spix_back,
    571                                                            x, y, 0, 0,
    572                                                            rotation)) {
    573             pSecondaryScrPriv->rrDisableSharedPixmapFlipping(crtc);
    574             goto fail;
    575         }
    576 
    577         primary->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 (!pSecondaryScrPriv->rrCrtcSetScanoutPixmap(crtc, spix_front)) {
    597         rrDestroySharedPixmap(crtc, spix_front);
    598         ErrorF("randr: failed to set shadow secondary pixmap\n");
    599         return FALSE;
    600     }
    601     crtc->scanout_pixmap = spix_front;
    602 
    603     primary->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation);
    604 
    605     return TRUE;
    606 }
    607 
    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
    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 secondary;
    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 primarys
    645        and all their output secondarys */
    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(secondary, &pScreen->secondary_list, secondary_head) {
    670         rrScrPrivPtr    secondary_priv = rrGetScrPriv(secondary);
    671 
    672         if (!secondary->is_output_secondary)
    673             continue;
    674 
    675         for (c = 0; c < secondary_priv->numCrtcs; c++) {
    676             RRCrtcPtr secondary_crtc = secondary_priv->crtcs[c];
    677 
    678             if (secondary_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 (!secondary_crtc->mode)
    692                     continue;
    693                 crtc_to_box(&newbox, secondary_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
    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 primary = pScreen->current_primary;
    760             int width = 0, height = 0;
    761 
    762             if (mode) {
    763                 width = mode->mode.width;
    764                 height = mode->mode.height;
    765             }
    766             ret = rrCheckPixmapBounding(primary, crtc,
    767                                         rotation, x, y, width, height);
    768             if (!ret)
    769                 return FALSE;
    770 
    771             if (pScreen->current_primary) {
    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
    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
    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
    866 RRCrtcDestroy(RRCrtcPtr crtc)
    867 {
    868     FreeResource(crtc->id, 0);
    869 }
    870 
    871 static int
    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
    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
    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 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 
    986 Bool RRCrtcExists(ScreenPtr pScreen, RRCrtcPtr findCrtc)
    987 {
    988     ScreenPtr secondary= NULL;
    989 
    990     if (RRCrtcInScreen(pScreen, findCrtc))
    991         return TRUE;
    992 
    993     xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
    994         if (!secondary->is_output_secondary)
    995             continue;
    996         if (RRCrtcInScreen(secondary, 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
   1011 RRCrtcGammaNotify(RRCrtcPtr crtc)
   1012 {
   1013     return TRUE;                /* not much going on here */
   1014 }
   1015 
   1016 static void
   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
   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
   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
   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
   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
   1136 RRCrtcInitErrorValue(void)
   1137 {
   1138     SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
   1139 }
   1140 
   1141 int
   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
   1275 ProcRRSetCrtcConfig(ClientPtr client)
   1276 {
   1277     REQUEST(xRRSetCrtcConfigReq);
   1278     xRRSetCrtcConfigReply rep;
   1279     ScreenPtr pScreen;
   1280     rrScrPrivPtr pScrPriv;
   1281     RRCrtcPtr crtc;
   1282     RRModePtr mode;
   1283     unsigned 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_primary->width;
   1429                 height = pScreen->current_primary->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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   1926 RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
   1927                         int *y)
   1928 {
   1929     rrScrPriv(pScreen);
   1930     Bool ret;
   1931     ScreenPtr secondary;
   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(secondary, &pScreen->secondary_list, secondary_head) {
   1943         if (!secondary->is_output_secondary)
   1944             continue;
   1945 
   1946         ret = check_all_screen_crtcs(secondary, 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(secondary, &pScreen->secondary_list, secondary_head) {
   1957         if (!secondary->is_output_secondary)
   1958             continue;
   1959 
   1960         ret = constrain_all_screen_crtcs(pDev, secondary, x, y);
   1961         if (ret == TRUE)
   1962             return;
   1963     }
   1964 }
   1965 
   1966 Bool
   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
   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_secondary)
   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 }