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