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