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