rrcrtc.c revision 35c4bbdf
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
28RESTYPE RRCrtcType;
29
30/*
31 * Notify the CRTC of some change
32 */
33void
34RRCrtcChanged(RRCrtcPtr crtc, Bool layoutChanged)
35{
36    ScreenPtr pScreen = crtc->pScreen;
37
38    crtc->changed = TRUE;
39    if (pScreen) {
40        rrScrPriv(pScreen);
41
42        RRSetChanged(pScreen);
43        /*
44         * Send ConfigureNotify on any layout change
45         */
46        if (layoutChanged)
47            pScrPriv->layoutChanged = TRUE;
48    }
49}
50
51/*
52 * Create a CRTC
53 */
54RRCrtcPtr
55RRCrtcCreate(ScreenPtr pScreen, void *devPrivate)
56{
57    RRCrtcPtr crtc;
58    RRCrtcPtr *crtcs;
59    rrScrPrivPtr pScrPriv;
60
61    if (!RRInit())
62        return NULL;
63
64    pScrPriv = rrGetScrPriv(pScreen);
65
66    /* make space for the crtc pointer */
67    if (pScrPriv->numCrtcs)
68        crtcs = reallocarray(pScrPriv->crtcs,
69                             pScrPriv->numCrtcs + 1, sizeof(RRCrtcPtr));
70    else
71        crtcs = malloc(sizeof(RRCrtcPtr));
72    if (!crtcs)
73        return FALSE;
74    pScrPriv->crtcs = crtcs;
75
76    crtc = calloc(1, sizeof(RRCrtcRec));
77    if (!crtc)
78        return NULL;
79    crtc->id = FakeClientID(0);
80    crtc->pScreen = pScreen;
81    crtc->mode = NULL;
82    crtc->x = 0;
83    crtc->y = 0;
84    crtc->rotation = RR_Rotate_0;
85    crtc->rotations = RR_Rotate_0;
86    crtc->outputs = NULL;
87    crtc->numOutputs = 0;
88    crtc->gammaSize = 0;
89    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
90    crtc->changed = FALSE;
91    crtc->devPrivate = devPrivate;
92    RRTransformInit(&crtc->client_pending_transform);
93    RRTransformInit(&crtc->client_current_transform);
94    pixman_transform_init_identity(&crtc->transform);
95    pixman_f_transform_init_identity(&crtc->f_transform);
96    pixman_f_transform_init_identity(&crtc->f_inverse);
97
98    if (!AddResource(crtc->id, RRCrtcType, (void *) crtc))
99        return NULL;
100
101    /* attach the screen and crtc together */
102    crtc->pScreen = pScreen;
103    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
104
105    RRResourcesChanged(pScreen);
106
107    return crtc;
108}
109
110/*
111 * Set the allowed rotations on a CRTC
112 */
113void
114RRCrtcSetRotations(RRCrtcPtr crtc, Rotation rotations)
115{
116    crtc->rotations = rotations;
117}
118
119/*
120 * Set whether transforms are allowed on a CRTC
121 */
122void
123RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
124{
125    crtc->transforms = transforms;
126}
127
128/*
129 * Notify the extension that the Crtc has been reconfigured,
130 * the driver calls this whenever it has updated the mode
131 */
132Bool
133RRCrtcNotify(RRCrtcPtr crtc,
134             RRModePtr mode,
135             int x,
136             int y,
137             Rotation rotation,
138             RRTransformPtr transform, int numOutputs, RROutputPtr * outputs)
139{
140    int i, j;
141
142    /*
143     * Check to see if any of the new outputs were
144     * not in the old list and mark them as changed
145     */
146    for (i = 0; i < numOutputs; i++) {
147        for (j = 0; j < crtc->numOutputs; j++)
148            if (outputs[i] == crtc->outputs[j])
149                break;
150        if (j == crtc->numOutputs) {
151            outputs[i]->crtc = crtc;
152            RROutputChanged(outputs[i], FALSE);
153            RRCrtcChanged(crtc, FALSE);
154        }
155    }
156    /*
157     * Check to see if any of the old outputs are
158     * not in the new list and mark them as changed
159     */
160    for (j = 0; j < crtc->numOutputs; j++) {
161        for (i = 0; i < numOutputs; i++)
162            if (outputs[i] == crtc->outputs[j])
163                break;
164        if (i == numOutputs) {
165            if (crtc->outputs[j]->crtc == crtc)
166                crtc->outputs[j]->crtc = NULL;
167            RROutputChanged(crtc->outputs[j], FALSE);
168            RRCrtcChanged(crtc, FALSE);
169        }
170    }
171    /*
172     * Reallocate the crtc output array if necessary
173     */
174    if (numOutputs != crtc->numOutputs) {
175        RROutputPtr *newoutputs;
176
177        if (numOutputs) {
178            if (crtc->numOutputs)
179                newoutputs = reallocarray(crtc->outputs,
180                                          numOutputs, sizeof(RROutputPtr));
181            else
182                newoutputs = xallocarray(numOutputs, sizeof(RROutputPtr));
183            if (!newoutputs)
184                return FALSE;
185        }
186        else {
187            free(crtc->outputs);
188            newoutputs = NULL;
189        }
190        crtc->outputs = newoutputs;
191        crtc->numOutputs = numOutputs;
192    }
193    /*
194     * Copy the new list of outputs into the crtc
195     */
196    memcpy(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr));
197    /*
198     * Update remaining crtc fields
199     */
200    if (mode != crtc->mode) {
201        if (crtc->mode)
202            RRModeDestroy(crtc->mode);
203        crtc->mode = mode;
204        if (mode != NULL)
205            mode->refcnt++;
206        RRCrtcChanged(crtc, TRUE);
207    }
208    if (x != crtc->x) {
209        crtc->x = x;
210        RRCrtcChanged(crtc, TRUE);
211    }
212    if (y != crtc->y) {
213        crtc->y = y;
214        RRCrtcChanged(crtc, TRUE);
215    }
216    if (rotation != crtc->rotation) {
217        crtc->rotation = rotation;
218        RRCrtcChanged(crtc, TRUE);
219    }
220    if (!RRTransformEqual(transform, &crtc->client_current_transform)) {
221        RRTransformCopy(&crtc->client_current_transform, transform);
222        RRCrtcChanged(crtc, TRUE);
223    }
224    if (crtc->changed && mode) {
225        RRTransformCompute(x, y,
226                           mode->mode.width, mode->mode.height,
227                           rotation,
228                           &crtc->client_current_transform,
229                           &crtc->transform, &crtc->f_transform,
230                           &crtc->f_inverse);
231    }
232    return TRUE;
233}
234
235void
236RRDeliverCrtcEvent(ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
237{
238    ScreenPtr pScreen = pWin->drawable.pScreen;
239
240    rrScrPriv(pScreen);
241    RRModePtr mode = crtc->mode;
242
243    xRRCrtcChangeNotifyEvent ce = {
244        .type = RRNotify + RREventBase,
245        .subCode = RRNotify_CrtcChange,
246        .timestamp = pScrPriv->lastSetTime.milliseconds,
247        .window = pWin->drawable.id,
248        .crtc = crtc->id,
249        .mode = mode ? mode->mode.id : None,
250        .rotation = crtc->rotation,
251        .x = mode ? crtc->x : 0,
252        .y = mode ? crtc->y : 0,
253        .width = mode ? mode->mode.width : 0,
254        .height = mode ? mode->mode.height : 0
255    };
256    WriteEventsToClient(client, 1, (xEvent *) &ce);
257}
258
259static Bool
260RRCrtcPendingProperties(RRCrtcPtr crtc)
261{
262    ScreenPtr pScreen = crtc->pScreen;
263
264    rrScrPriv(pScreen);
265    int o;
266
267    for (o = 0; o < pScrPriv->numOutputs; o++) {
268        RROutputPtr output = pScrPriv->outputs[o];
269
270        if (output->crtc == crtc && output->pendingProperties)
271            return TRUE;
272    }
273    return FALSE;
274}
275
276static void
277crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
278{
279    *left = crtc->x;
280    *top = crtc->y;
281
282    switch (crtc->rotation) {
283    case RR_Rotate_0:
284    case RR_Rotate_180:
285    default:
286        *right = crtc->x + crtc->mode->mode.width;
287        *bottom = crtc->y + crtc->mode->mode.height;
288        return;
289    case RR_Rotate_90:
290    case RR_Rotate_270:
291        *right = crtc->x + crtc->mode->mode.height;
292        *bottom = crtc->y + crtc->mode->mode.width;
293        return;
294    }
295}
296
297/* overlapping counts as adjacent */
298static Bool
299crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
300{
301    /* left, right, top, bottom... */
302    int al, ar, at, ab;
303    int bl, br, bt, bb;
304    int cl, cr, ct, cb;         /* the overlap, if any */
305
306    crtc_bounds(a, &al, &ar, &at, &ab);
307    crtc_bounds(b, &bl, &br, &bt, &bb);
308
309    cl = max(al, bl);
310    cr = min(ar, br);
311    ct = max(at, bt);
312    cb = min(ab, bb);
313
314    return (cl <= cr) && (ct <= cb);
315}
316
317/* Depth-first search and mark all CRTCs reachable from cur */
318static void
319mark_crtcs(rrScrPrivPtr pScrPriv, int *reachable, int cur)
320{
321    int i;
322
323    reachable[cur] = TRUE;
324    for (i = 0; i < pScrPriv->numCrtcs; ++i) {
325        if (reachable[i] || !pScrPriv->crtcs[i]->mode)
326            continue;
327        if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
328            mark_crtcs(pScrPriv, reachable, i);
329    }
330}
331
332static void
333RRComputeContiguity(ScreenPtr pScreen)
334{
335    rrScrPriv(pScreen);
336    Bool discontiguous = TRUE;
337    int i, n = pScrPriv->numCrtcs;
338
339    int *reachable = calloc(n, sizeof(int));
340
341    if (!reachable)
342        goto out;
343
344    /* Find first enabled CRTC and start search for reachable CRTCs from it */
345    for (i = 0; i < n; ++i) {
346        if (pScrPriv->crtcs[i]->mode) {
347            mark_crtcs(pScrPriv, reachable, i);
348            break;
349        }
350    }
351
352    /* Check that all enabled CRTCs were marked as reachable */
353    for (i = 0; i < n; ++i)
354        if (pScrPriv->crtcs[i]->mode && !reachable[i])
355            goto out;
356
357    discontiguous = FALSE;
358
359 out:
360    free(reachable);
361    pScrPriv->discontiguous = discontiguous;
362}
363
364void
365RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
366{
367    ScreenPtr master = crtc->pScreen->current_master;
368    PixmapPtr mscreenpix;
369    rrScrPriv(crtc->pScreen);
370
371    mscreenpix = master->GetScreenPixmap(master);
372
373    pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
374    if (crtc->scanout_pixmap) {
375        master->StopPixmapTracking(mscreenpix, crtc->scanout_pixmap);
376        /*
377         * Unref the pixmap twice: once for the original reference, and once
378         * for the reference implicitly added by PixmapShareToSlave.
379         */
380        master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap);
381        master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap);
382        crtc->pScreen->DestroyPixmap(crtc->scanout_pixmap);
383    }
384    crtc->scanout_pixmap = NULL;
385    RRCrtcChanged(crtc, TRUE);
386}
387
388static Bool
389rrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height,
390                     int x, int y, Rotation rotation)
391{
392    PixmapPtr mpix, spix;
393    ScreenPtr master = crtc->pScreen->current_master;
394    Bool ret;
395    int depth;
396    PixmapPtr mscreenpix;
397    PixmapPtr protopix = master->GetScreenPixmap(master);
398    rrScrPriv(crtc->pScreen);
399
400    /* create a pixmap on the master screen,
401       then get a shared handle for it
402       create a shared pixmap on the slave screen using the handle
403       set the master screen to do dirty updates to the shared pixmap
404       from the screen pixmap.
405       set slave screen to scanout shared linear pixmap
406    */
407
408    mscreenpix = master->GetScreenPixmap(master);
409    depth = protopix->drawable.depth;
410
411    if (crtc->scanout_pixmap)
412        RRCrtcDetachScanoutPixmap(crtc);
413
414    if (width == 0 && height == 0) {
415        return TRUE;
416    }
417
418    mpix = master->CreatePixmap(master, width, height, depth,
419                                CREATE_PIXMAP_USAGE_SHARED);
420    if (!mpix)
421        return FALSE;
422
423    spix = PixmapShareToSlave(mpix, crtc->pScreen);
424    if (spix == NULL) {
425        master->DestroyPixmap(mpix);
426        return FALSE;
427    }
428
429    ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix);
430    if (ret == FALSE) {
431        ErrorF("randr: failed to set shadow slave pixmap\n");
432        return FALSE;
433    }
434
435    crtc->scanout_pixmap = spix;
436
437    master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation);
438    return TRUE;
439}
440
441static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
442{
443    box->x1 = crtc->x;
444    box->y1 = crtc->y;
445    switch (crtc->rotation) {
446    case RR_Rotate_0:
447    case RR_Rotate_180:
448    default:
449        box->x2 = crtc->x + crtc->mode->mode.width;
450        box->y2 = crtc->y + crtc->mode->mode.height;
451        break;
452    case RR_Rotate_90:
453    case RR_Rotate_270:
454        box->x2 = crtc->x + crtc->mode->mode.height;
455        box->y2 = crtc->y + crtc->mode->mode.width;
456        break;
457    }
458}
459
460static Bool
461rrCheckPixmapBounding(ScreenPtr pScreen,
462                      RRCrtcPtr rr_crtc, Rotation rotation,
463                      int x, int y, int w, int h)
464{
465    RegionRec root_pixmap_region, total_region, new_crtc_region;
466    int c;
467    BoxRec newbox;
468    BoxPtr newsize;
469    ScreenPtr slave;
470    int new_width, new_height;
471    PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
472    rrScrPriv(pScreen);
473
474    PixmapRegionInit(&root_pixmap_region, screen_pixmap);
475    RegionInit(&total_region, NULL, 0);
476
477    /* have to iterate all the crtcs of the attached gpu masters
478       and all their output slaves */
479    for (c = 0; c < pScrPriv->numCrtcs; c++) {
480        RRCrtcPtr crtc = pScrPriv->crtcs[c];
481
482        if (crtc == rr_crtc) {
483            newbox.x1 = x;
484            newbox.y1 = y;
485            if (rotation == RR_Rotate_90 ||
486                rotation == RR_Rotate_270) {
487                newbox.x2 = x + h;
488                newbox.y2 = y + w;
489            } else {
490                newbox.x2 = x + w;
491                newbox.y2 = y + h;
492            }
493        } else {
494            if (!crtc->mode)
495                continue;
496            crtc_to_box(&newbox, crtc);
497        }
498        RegionInit(&new_crtc_region, &newbox, 1);
499        RegionUnion(&total_region, &total_region, &new_crtc_region);
500    }
501
502    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
503        rrScrPrivPtr    slave_priv = rrGetScrPriv(slave);
504        for (c = 0; c < slave_priv->numCrtcs; c++) {
505            RRCrtcPtr slave_crtc = slave_priv->crtcs[c];
506
507            if (slave_crtc == rr_crtc) {
508                newbox.x1 = x;
509                newbox.y1 = y;
510                if (rotation == RR_Rotate_90 ||
511                    rotation == RR_Rotate_270) {
512                    newbox.x2 = x + h;
513                    newbox.y2 = y + w;
514                } else {
515                    newbox.x2 = x + w;
516                    newbox.y2 = y + h;
517                }
518            }
519            else {
520                if (!slave_crtc->mode)
521                    continue;
522                crtc_to_box(&newbox, slave_crtc);
523            }
524            RegionInit(&new_crtc_region, &newbox, 1);
525            RegionUnion(&total_region, &total_region, &new_crtc_region);
526        }
527    }
528
529    newsize = RegionExtents(&total_region);
530    new_width = newsize->x2 - newsize->x1;
531    new_height = newsize->y2 - newsize->y1;
532
533    if (new_width == screen_pixmap->drawable.width &&
534        new_height == screen_pixmap->drawable.height) {
535    } else {
536        pScrPriv->rrScreenSetSize(pScreen, new_width, new_height, 0, 0);
537    }
538
539    /* set shatters TODO */
540    return TRUE;
541}
542
543/*
544 * Request that the Crtc be reconfigured
545 */
546Bool
547RRCrtcSet(RRCrtcPtr crtc,
548          RRModePtr mode,
549          int x,
550          int y, Rotation rotation, int numOutputs, RROutputPtr * outputs)
551{
552    ScreenPtr pScreen = crtc->pScreen;
553    Bool ret = FALSE;
554    Bool recompute = TRUE;
555    Bool crtcChanged;
556    int  o;
557
558    rrScrPriv(pScreen);
559
560    crtcChanged = FALSE;
561    for (o = 0; o < numOutputs; o++) {
562        if (outputs[o] && outputs[o]->crtc != crtc) {
563            crtcChanged = TRUE;
564            break;
565        }
566    }
567
568    /* See if nothing changed */
569    if (crtc->mode == mode &&
570        crtc->x == x &&
571        crtc->y == y &&
572        crtc->rotation == rotation &&
573        crtc->numOutputs == numOutputs &&
574        !memcmp(crtc->outputs, outputs, numOutputs * sizeof(RROutputPtr)) &&
575        !RRCrtcPendingProperties(crtc) && !RRCrtcPendingTransform(crtc) &&
576        !crtcChanged) {
577        recompute = FALSE;
578        ret = TRUE;
579    }
580    else {
581        if (pScreen->isGPU) {
582            ScreenPtr master = pScreen->current_master;
583            int width = 0, height = 0;
584
585            if (mode) {
586                width = mode->mode.width;
587                height = mode->mode.height;
588            }
589            ret = rrCheckPixmapBounding(master, crtc,
590                                        rotation, x, y, width, height);
591            if (!ret)
592                return FALSE;
593
594            if (pScreen->current_master) {
595                ret = rrCreateSharedPixmap(crtc, width, height, x, y, rotation);
596            }
597        }
598#if RANDR_12_INTERFACE
599        if (pScrPriv->rrCrtcSet) {
600            ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
601                                          rotation, numOutputs, outputs);
602        }
603        else
604#endif
605        {
606#if RANDR_10_INTERFACE
607            if (pScrPriv->rrSetConfig) {
608                RRScreenSize size;
609                RRScreenRate rate;
610
611                if (!mode) {
612                    RRCrtcNotify(crtc, NULL, x, y, rotation, NULL, 0, NULL);
613                    ret = TRUE;
614                }
615                else {
616                    size.width = mode->mode.width;
617                    size.height = mode->mode.height;
618                    if (outputs[0]->mmWidth && outputs[0]->mmHeight) {
619                        size.mmWidth = outputs[0]->mmWidth;
620                        size.mmHeight = outputs[0]->mmHeight;
621                    }
622                    else {
623                        size.mmWidth = pScreen->mmWidth;
624                        size.mmHeight = pScreen->mmHeight;
625                    }
626                    size.nRates = 1;
627                    rate.rate = RRVerticalRefresh(&mode->mode);
628                    size.pRates = &rate;
629                    ret =
630                        (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate,
631                                                  &size);
632                    /*
633                     * Old 1.0 interface tied screen size to mode size
634                     */
635                    if (ret) {
636                        RRCrtcNotify(crtc, mode, x, y, rotation, NULL, 1,
637                                     outputs);
638                        RRScreenSizeNotify(pScreen);
639                    }
640                }
641            }
642#endif
643        }
644        if (ret) {
645
646            RRTellChanged(pScreen);
647
648            for (o = 0; o < numOutputs; o++)
649                RRPostPendingProperties(outputs[o]);
650        }
651    }
652
653    if (recompute)
654        RRComputeContiguity(pScreen);
655
656    return ret;
657}
658
659/*
660 * Return crtc transform
661 */
662RRTransformPtr
663RRCrtcGetTransform(RRCrtcPtr crtc)
664{
665    RRTransformPtr transform = &crtc->client_pending_transform;
666
667    if (pixman_transform_is_identity(&transform->transform))
668        return NULL;
669    return transform;
670}
671
672/*
673 * Check whether the pending and current transforms are the same
674 */
675Bool
676RRCrtcPendingTransform(RRCrtcPtr crtc)
677{
678    return memcmp(&crtc->client_current_transform.transform,
679                  &crtc->client_pending_transform.transform,
680                  sizeof(PictTransform)) != 0;
681}
682
683/*
684 * Destroy a Crtc at shutdown
685 */
686void
687RRCrtcDestroy(RRCrtcPtr crtc)
688{
689    FreeResource(crtc->id, 0);
690}
691
692static int
693RRCrtcDestroyResource(void *value, XID pid)
694{
695    RRCrtcPtr crtc = (RRCrtcPtr) value;
696    ScreenPtr pScreen = crtc->pScreen;
697
698    if (pScreen) {
699        rrScrPriv(pScreen);
700        int i;
701
702        for (i = 0; i < pScrPriv->numCrtcs; i++) {
703            if (pScrPriv->crtcs[i] == crtc) {
704                memmove(pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
705                        (pScrPriv->numCrtcs - (i + 1)) * sizeof(RRCrtcPtr));
706                --pScrPriv->numCrtcs;
707                break;
708            }
709        }
710
711        RRResourcesChanged(pScreen);
712    }
713
714    if (crtc->scanout_pixmap)
715        RRCrtcDetachScanoutPixmap(crtc);
716    free(crtc->gammaRed);
717    if (crtc->mode)
718        RRModeDestroy(crtc->mode);
719    free(crtc);
720    return 1;
721}
722
723/*
724 * Request that the Crtc gamma be changed
725 */
726
727Bool
728RRCrtcGammaSet(RRCrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue)
729{
730    Bool ret = TRUE;
731
732#if RANDR_12_INTERFACE
733    ScreenPtr pScreen = crtc->pScreen;
734#endif
735
736    memcpy(crtc->gammaRed, red, crtc->gammaSize * sizeof(CARD16));
737    memcpy(crtc->gammaGreen, green, crtc->gammaSize * sizeof(CARD16));
738    memcpy(crtc->gammaBlue, blue, crtc->gammaSize * sizeof(CARD16));
739#if RANDR_12_INTERFACE
740    if (pScreen) {
741        rrScrPriv(pScreen);
742        if (pScrPriv->rrCrtcSetGamma)
743            ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
744    }
745#endif
746    return ret;
747}
748
749/*
750 * Request current gamma back from the DDX (if possible).
751 * This includes gamma size.
752 */
753Bool
754RRCrtcGammaGet(RRCrtcPtr crtc)
755{
756    Bool ret = TRUE;
757
758#if RANDR_12_INTERFACE
759    ScreenPtr pScreen = crtc->pScreen;
760#endif
761
762#if RANDR_12_INTERFACE
763    if (pScreen) {
764        rrScrPriv(pScreen);
765        if (pScrPriv->rrCrtcGetGamma)
766            ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
767    }
768#endif
769    return ret;
770}
771
772/*
773 * Notify the extension that the Crtc gamma has been changed
774 * The driver calls this whenever it has changed the gamma values
775 * in the RRCrtcRec
776 */
777
778Bool
779RRCrtcGammaNotify(RRCrtcPtr crtc)
780{
781    return TRUE;                /* not much going on here */
782}
783
784static void
785RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
786                     int *width, int *height)
787{
788    BoxRec box;
789
790    if (mode == NULL) {
791        *width = 0;
792        *height = 0;
793        return;
794    }
795
796    box.x1 = 0;
797    box.y1 = 0;
798    box.x2 = mode->mode.width;
799    box.y2 = mode->mode.height;
800
801    pixman_transform_bounds(transform, &box);
802    *width = box.x2 - box.x1;
803    *height = box.y2 - box.y1;
804}
805
806/**
807 * Returns the width/height that the crtc scans out from the framebuffer
808 */
809void
810RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
811{
812    RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
813}
814
815/*
816 * Set the size of the gamma table at server startup time
817 */
818
819Bool
820RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
821{
822    CARD16 *gamma;
823
824    if (size == crtc->gammaSize)
825        return TRUE;
826    if (size) {
827        gamma = xallocarray(size, 3 * sizeof(CARD16));
828        if (!gamma)
829            return FALSE;
830    }
831    else
832        gamma = NULL;
833    free(crtc->gammaRed);
834    crtc->gammaRed = gamma;
835    crtc->gammaGreen = gamma + size;
836    crtc->gammaBlue = gamma + size * 2;
837    crtc->gammaSize = size;
838    return TRUE;
839}
840
841/*
842 * Set the pending CRTC transformation
843 */
844
845int
846RRCrtcTransformSet(RRCrtcPtr crtc,
847                   PictTransformPtr transform,
848                   struct pixman_f_transform *f_transform,
849                   struct pixman_f_transform *f_inverse,
850                   char *filter_name,
851                   int filter_len, xFixed * params, int nparams)
852{
853    PictFilterPtr filter = NULL;
854    int width = 0, height = 0;
855
856    if (!crtc->transforms)
857        return BadValue;
858
859    if (filter_len) {
860        filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
861        if (!filter)
862            return BadName;
863        if (filter->ValidateParams) {
864            if (!filter->ValidateParams(crtc->pScreen, filter->id,
865                                        params, nparams, &width, &height))
866                return BadMatch;
867        }
868        else {
869            width = filter->width;
870            height = filter->height;
871        }
872    }
873    else {
874        if (nparams)
875            return BadMatch;
876    }
877    if (!RRTransformSetFilter(&crtc->client_pending_transform,
878                              filter, params, nparams, width, height))
879        return BadAlloc;
880
881    crtc->client_pending_transform.transform = *transform;
882    crtc->client_pending_transform.f_transform = *f_transform;
883    crtc->client_pending_transform.f_inverse = *f_inverse;
884    return Success;
885}
886
887/*
888 * Initialize crtc type
889 */
890Bool
891RRCrtcInit(void)
892{
893    RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
894    if (!RRCrtcType)
895        return FALSE;
896
897    return TRUE;
898}
899
900/*
901 * Initialize crtc type error value
902 */
903void
904RRCrtcInitErrorValue(void)
905{
906    SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
907}
908
909int
910ProcRRGetCrtcInfo(ClientPtr client)
911{
912    REQUEST(xRRGetCrtcInfoReq);
913    xRRGetCrtcInfoReply rep;
914    RRCrtcPtr crtc;
915    CARD8 *extra;
916    unsigned long extraLen;
917    ScreenPtr pScreen;
918    rrScrPrivPtr pScrPriv;
919    RRModePtr mode;
920    RROutput *outputs;
921    RROutput *possible;
922    int i, j, k;
923    int width, height;
924    BoxRec panned_area;
925
926    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
927    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
928
929    /* All crtcs must be associated with screens before client
930     * requests are processed
931     */
932    pScreen = crtc->pScreen;
933    pScrPriv = rrGetScrPriv(pScreen);
934
935    mode = crtc->mode;
936
937    rep = (xRRGetCrtcInfoReply) {
938        .type = X_Reply,
939        .status = RRSetConfigSuccess,
940        .sequenceNumber = client->sequence,
941        .length = 0,
942        .timestamp = pScrPriv->lastSetTime.milliseconds
943    };
944    if (pScrPriv->rrGetPanning &&
945        pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
946        (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
947    {
948        rep.x = panned_area.x1;
949        rep.y = panned_area.y1;
950        rep.width = panned_area.x2 - panned_area.x1;
951        rep.height = panned_area.y2 - panned_area.y1;
952    }
953    else {
954        RRCrtcGetScanoutSize(crtc, &width, &height);
955        rep.x = crtc->x;
956        rep.y = crtc->y;
957        rep.width = width;
958        rep.height = height;
959    }
960    rep.mode = mode ? mode->mode.id : 0;
961    rep.rotation = crtc->rotation;
962    rep.rotations = crtc->rotations;
963    rep.nOutput = crtc->numOutputs;
964    k = 0;
965    for (i = 0; i < pScrPriv->numOutputs; i++)
966        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
967            if (pScrPriv->outputs[i]->crtcs[j] == crtc)
968                k++;
969    rep.nPossibleOutput = k;
970
971    rep.length = rep.nOutput + rep.nPossibleOutput;
972
973    extraLen = rep.length << 2;
974    if (extraLen) {
975        extra = malloc(extraLen);
976        if (!extra)
977            return BadAlloc;
978    }
979    else
980        extra = NULL;
981
982    outputs = (RROutput *) extra;
983    possible = (RROutput *) (outputs + rep.nOutput);
984
985    for (i = 0; i < crtc->numOutputs; i++) {
986        outputs[i] = crtc->outputs[i]->id;
987        if (client->swapped)
988            swapl(&outputs[i]);
989    }
990    k = 0;
991    for (i = 0; i < pScrPriv->numOutputs; i++)
992        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
993            if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
994                possible[k] = pScrPriv->outputs[i]->id;
995                if (client->swapped)
996                    swapl(&possible[k]);
997                k++;
998            }
999
1000    if (client->swapped) {
1001        swaps(&rep.sequenceNumber);
1002        swapl(&rep.length);
1003        swapl(&rep.timestamp);
1004        swaps(&rep.x);
1005        swaps(&rep.y);
1006        swaps(&rep.width);
1007        swaps(&rep.height);
1008        swapl(&rep.mode);
1009        swaps(&rep.rotation);
1010        swaps(&rep.rotations);
1011        swaps(&rep.nOutput);
1012        swaps(&rep.nPossibleOutput);
1013    }
1014    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
1015    if (extraLen) {
1016        WriteToClient(client, extraLen, extra);
1017        free(extra);
1018    }
1019
1020    return Success;
1021}
1022
1023int
1024ProcRRSetCrtcConfig(ClientPtr client)
1025{
1026    REQUEST(xRRSetCrtcConfigReq);
1027    xRRSetCrtcConfigReply rep;
1028    ScreenPtr pScreen;
1029    rrScrPrivPtr pScrPriv;
1030    RRCrtcPtr crtc;
1031    RRModePtr mode;
1032    int numOutputs;
1033    RROutputPtr *outputs = NULL;
1034    RROutput *outputIds;
1035    TimeStamp time;
1036    Rotation rotation;
1037    int ret, i, j;
1038    CARD8 status;
1039
1040    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
1041    numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
1042
1043    VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
1044
1045    if (stuff->mode == None) {
1046        mode = NULL;
1047        if (numOutputs > 0)
1048            return BadMatch;
1049    }
1050    else {
1051        VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
1052        if (numOutputs == 0)
1053            return BadMatch;
1054    }
1055    if (numOutputs) {
1056        outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
1057        if (!outputs)
1058            return BadAlloc;
1059    }
1060    else
1061        outputs = NULL;
1062
1063    outputIds = (RROutput *) (stuff + 1);
1064    for (i = 0; i < numOutputs; i++) {
1065        ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
1066                                     RROutputType, client, DixSetAttrAccess);
1067        if (ret != Success) {
1068            free(outputs);
1069            return ret;
1070        }
1071        /* validate crtc for this output */
1072        for (j = 0; j < outputs[i]->numCrtcs; j++)
1073            if (outputs[i]->crtcs[j] == crtc)
1074                break;
1075        if (j == outputs[i]->numCrtcs) {
1076            free(outputs);
1077            return BadMatch;
1078        }
1079        /* validate mode for this output */
1080        for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
1081            RRModePtr m = (j < outputs[i]->numModes ?
1082                           outputs[i]->modes[j] :
1083                           outputs[i]->userModes[j - outputs[i]->numModes]);
1084            if (m == mode)
1085                break;
1086        }
1087        if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
1088            free(outputs);
1089            return BadMatch;
1090        }
1091    }
1092    /* validate clones */
1093    for (i = 0; i < numOutputs; i++) {
1094        for (j = 0; j < numOutputs; j++) {
1095            int k;
1096
1097            if (i == j)
1098                continue;
1099            for (k = 0; k < outputs[i]->numClones; k++) {
1100                if (outputs[i]->clones[k] == outputs[j])
1101                    break;
1102            }
1103            if (k == outputs[i]->numClones) {
1104                free(outputs);
1105                return BadMatch;
1106            }
1107        }
1108    }
1109
1110    pScreen = crtc->pScreen;
1111    pScrPriv = rrGetScrPriv(pScreen);
1112
1113    time = ClientTimeToServerTime(stuff->timestamp);
1114
1115    if (!pScrPriv) {
1116        time = currentTime;
1117        status = RRSetConfigFailed;
1118        goto sendReply;
1119    }
1120
1121    /*
1122     * Validate requested rotation
1123     */
1124    rotation = (Rotation) stuff->rotation;
1125
1126    /* test the rotation bits only! */
1127    switch (rotation & 0xf) {
1128    case RR_Rotate_0:
1129    case RR_Rotate_90:
1130    case RR_Rotate_180:
1131    case RR_Rotate_270:
1132        break;
1133    default:
1134        /*
1135         * Invalid rotation
1136         */
1137        client->errorValue = stuff->rotation;
1138        free(outputs);
1139        return BadValue;
1140    }
1141
1142    if (mode) {
1143        if ((~crtc->rotations) & rotation) {
1144            /*
1145             * requested rotation or reflection not supported by screen
1146             */
1147            client->errorValue = stuff->rotation;
1148            free(outputs);
1149            return BadMatch;
1150        }
1151
1152#ifdef RANDR_12_INTERFACE
1153        /*
1154         * Check screen size bounds if the DDX provides a 1.2 interface
1155         * for setting screen size. Else, assume the CrtcSet sets
1156         * the size along with the mode. If the driver supports transforms,
1157         * then it must allow crtcs to display a subset of the screen, so
1158         * only do this check for drivers without transform support.
1159         */
1160        if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
1161            int source_width;
1162            int source_height;
1163            PictTransform transform;
1164            struct pixman_f_transform f_transform, f_inverse;
1165            int width, height;
1166
1167            if (pScreen->isGPU) {
1168                width = pScreen->current_master->width;
1169                height = pScreen->current_master->height;
1170            }
1171            else {
1172                width = pScreen->width;
1173                height = pScreen->height;
1174            }
1175
1176            RRTransformCompute(stuff->x, stuff->y,
1177                               mode->mode.width, mode->mode.height,
1178                               rotation,
1179                               &crtc->client_pending_transform,
1180                               &transform, &f_transform, &f_inverse);
1181
1182            RRModeGetScanoutSize(mode, &transform, &source_width,
1183                                 &source_height);
1184            if (stuff->x + source_width > width) {
1185                client->errorValue = stuff->x;
1186                free(outputs);
1187                return BadValue;
1188            }
1189
1190            if (stuff->y + source_height > height) {
1191                client->errorValue = stuff->y;
1192                free(outputs);
1193                return BadValue;
1194            }
1195        }
1196#endif
1197    }
1198
1199    if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
1200                   rotation, numOutputs, outputs)) {
1201        status = RRSetConfigFailed;
1202        goto sendReply;
1203    }
1204    status = RRSetConfigSuccess;
1205    pScrPriv->lastSetTime = time;
1206
1207 sendReply:
1208    free(outputs);
1209
1210    rep = (xRRSetCrtcConfigReply) {
1211        .type = X_Reply,
1212        .status = status,
1213        .sequenceNumber = client->sequence,
1214        .length = 0,
1215        .newTimestamp = pScrPriv->lastSetTime.milliseconds
1216    };
1217
1218    if (client->swapped) {
1219        swaps(&rep.sequenceNumber);
1220        swapl(&rep.length);
1221        swapl(&rep.newTimestamp);
1222    }
1223    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
1224
1225    return Success;
1226}
1227
1228int
1229ProcRRGetPanning(ClientPtr client)
1230{
1231    REQUEST(xRRGetPanningReq);
1232    xRRGetPanningReply rep;
1233    RRCrtcPtr crtc;
1234    ScreenPtr pScreen;
1235    rrScrPrivPtr pScrPriv;
1236    BoxRec total;
1237    BoxRec tracking;
1238    INT16 border[4];
1239
1240    REQUEST_SIZE_MATCH(xRRGetPanningReq);
1241    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1242
1243    /* All crtcs must be associated with screens before client
1244     * requests are processed
1245     */
1246    pScreen = crtc->pScreen;
1247    pScrPriv = rrGetScrPriv(pScreen);
1248
1249    if (!pScrPriv)
1250        return RRErrorBase + BadRRCrtc;
1251
1252    rep = (xRRGetPanningReply) {
1253        .type = X_Reply,
1254        .status = RRSetConfigSuccess,
1255        .sequenceNumber = client->sequence,
1256        .length = 1,
1257        .timestamp = pScrPriv->lastSetTime.milliseconds
1258    };
1259
1260    if (pScrPriv->rrGetPanning &&
1261        pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
1262        rep.left = total.x1;
1263        rep.top = total.y1;
1264        rep.width = total.x2 - total.x1;
1265        rep.height = total.y2 - total.y1;
1266        rep.track_left = tracking.x1;
1267        rep.track_top = tracking.y1;
1268        rep.track_width = tracking.x2 - tracking.x1;
1269        rep.track_height = tracking.y2 - tracking.y1;
1270        rep.border_left = border[0];
1271        rep.border_top = border[1];
1272        rep.border_right = border[2];
1273        rep.border_bottom = border[3];
1274    }
1275
1276    if (client->swapped) {
1277        swaps(&rep.sequenceNumber);
1278        swapl(&rep.length);
1279        swapl(&rep.timestamp);
1280        swaps(&rep.left);
1281        swaps(&rep.top);
1282        swaps(&rep.width);
1283        swaps(&rep.height);
1284        swaps(&rep.track_left);
1285        swaps(&rep.track_top);
1286        swaps(&rep.track_width);
1287        swaps(&rep.track_height);
1288        swaps(&rep.border_left);
1289        swaps(&rep.border_top);
1290        swaps(&rep.border_right);
1291        swaps(&rep.border_bottom);
1292    }
1293    WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
1294    return Success;
1295}
1296
1297int
1298ProcRRSetPanning(ClientPtr client)
1299{
1300    REQUEST(xRRSetPanningReq);
1301    xRRSetPanningReply rep;
1302    RRCrtcPtr crtc;
1303    ScreenPtr pScreen;
1304    rrScrPrivPtr pScrPriv;
1305    TimeStamp time;
1306    BoxRec total;
1307    BoxRec tracking;
1308    INT16 border[4];
1309    CARD8 status;
1310
1311    REQUEST_SIZE_MATCH(xRRSetPanningReq);
1312    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1313
1314    /* All crtcs must be associated with screens before client
1315     * requests are processed
1316     */
1317    pScreen = crtc->pScreen;
1318    pScrPriv = rrGetScrPriv(pScreen);
1319
1320    if (!pScrPriv) {
1321        time = currentTime;
1322        status = RRSetConfigFailed;
1323        goto sendReply;
1324    }
1325
1326    time = ClientTimeToServerTime(stuff->timestamp);
1327
1328    if (!pScrPriv->rrGetPanning)
1329        return RRErrorBase + BadRRCrtc;
1330
1331    total.x1 = stuff->left;
1332    total.y1 = stuff->top;
1333    total.x2 = total.x1 + stuff->width;
1334    total.y2 = total.y1 + stuff->height;
1335    tracking.x1 = stuff->track_left;
1336    tracking.y1 = stuff->track_top;
1337    tracking.x2 = tracking.x1 + stuff->track_width;
1338    tracking.y2 = tracking.y1 + stuff->track_height;
1339    border[0] = stuff->border_left;
1340    border[1] = stuff->border_top;
1341    border[2] = stuff->border_right;
1342    border[3] = stuff->border_bottom;
1343
1344    if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
1345        return BadMatch;
1346
1347    pScrPriv->lastSetTime = time;
1348
1349    status = RRSetConfigSuccess;
1350
1351 sendReply:
1352    rep = (xRRSetPanningReply) {
1353        .type = X_Reply,
1354        .status = status,
1355        .sequenceNumber = client->sequence,
1356        .length = 0,
1357        .newTimestamp = pScrPriv->lastSetTime.milliseconds
1358    };
1359
1360    if (client->swapped) {
1361        swaps(&rep.sequenceNumber);
1362        swapl(&rep.length);
1363        swapl(&rep.newTimestamp);
1364    }
1365    WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
1366    return Success;
1367}
1368
1369int
1370ProcRRGetCrtcGammaSize(ClientPtr client)
1371{
1372    REQUEST(xRRGetCrtcGammaSizeReq);
1373    xRRGetCrtcGammaSizeReply reply;
1374    RRCrtcPtr crtc;
1375
1376    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1377    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1378
1379    /* Gamma retrieval failed, any better error? */
1380    if (!RRCrtcGammaGet(crtc))
1381        return RRErrorBase + BadRRCrtc;
1382
1383    reply = (xRRGetCrtcGammaSizeReply) {
1384        .type = X_Reply,
1385        .sequenceNumber = client->sequence,
1386        .length = 0,
1387        .size = crtc->gammaSize
1388    };
1389    if (client->swapped) {
1390        swaps(&reply.sequenceNumber);
1391        swapl(&reply.length);
1392        swaps(&reply.size);
1393    }
1394    WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
1395    return Success;
1396}
1397
1398int
1399ProcRRGetCrtcGamma(ClientPtr client)
1400{
1401    REQUEST(xRRGetCrtcGammaReq);
1402    xRRGetCrtcGammaReply reply;
1403    RRCrtcPtr crtc;
1404    unsigned long len;
1405    char *extra = NULL;
1406
1407    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1408    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1409
1410    /* Gamma retrieval failed, any better error? */
1411    if (!RRCrtcGammaGet(crtc))
1412        return RRErrorBase + BadRRCrtc;
1413
1414    len = crtc->gammaSize * 3 * 2;
1415
1416    if (crtc->gammaSize) {
1417        extra = malloc(len);
1418        if (!extra)
1419            return BadAlloc;
1420    }
1421
1422    reply = (xRRGetCrtcGammaReply) {
1423        .type = X_Reply,
1424        .sequenceNumber = client->sequence,
1425        .length = bytes_to_int32(len),
1426        .size = crtc->gammaSize
1427    };
1428    if (client->swapped) {
1429        swaps(&reply.sequenceNumber);
1430        swapl(&reply.length);
1431        swaps(&reply.size);
1432    }
1433    WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
1434    if (crtc->gammaSize) {
1435        memcpy(extra, crtc->gammaRed, len);
1436        client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
1437        WriteSwappedDataToClient(client, len, extra);
1438        free(extra);
1439    }
1440    return Success;
1441}
1442
1443int
1444ProcRRSetCrtcGamma(ClientPtr client)
1445{
1446    REQUEST(xRRSetCrtcGammaReq);
1447    RRCrtcPtr crtc;
1448    unsigned long len;
1449    CARD16 *red, *green, *blue;
1450
1451    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1452    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1453
1454    len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
1455    if (len < (stuff->size * 3 + 1) >> 1)
1456        return BadLength;
1457
1458    if (stuff->size != crtc->gammaSize)
1459        return BadMatch;
1460
1461    red = (CARD16 *) (stuff + 1);
1462    green = red + crtc->gammaSize;
1463    blue = green + crtc->gammaSize;
1464
1465    RRCrtcGammaSet(crtc, red, green, blue);
1466
1467    return Success;
1468}
1469
1470/* Version 1.3 additions */
1471
1472int
1473ProcRRSetCrtcTransform(ClientPtr client)
1474{
1475    REQUEST(xRRSetCrtcTransformReq);
1476    RRCrtcPtr crtc;
1477    PictTransform transform;
1478    struct pixman_f_transform f_transform, f_inverse;
1479    char *filter;
1480    int nbytes;
1481    xFixed *params;
1482    int nparams;
1483
1484    REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1485    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1486
1487    PictTransform_from_xRenderTransform(&transform, &stuff->transform);
1488    pixman_f_transform_from_pixman_transform(&f_transform, &transform);
1489    if (!pixman_f_transform_invert(&f_inverse, &f_transform))
1490        return BadMatch;
1491
1492    filter = (char *) (stuff + 1);
1493    nbytes = stuff->nbytesFilter;
1494    params = (xFixed *) (filter + pad_to_int32(nbytes));
1495    nparams = ((xFixed *) stuff + client->req_len) - params;
1496    if (nparams < 0)
1497        return BadLength;
1498
1499    return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
1500                              filter, nbytes, params, nparams);
1501}
1502
1503#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
1504
1505static int
1506transform_filter_length(RRTransformPtr transform)
1507{
1508    int nbytes, nparams;
1509
1510    if (transform->filter == NULL)
1511        return 0;
1512    nbytes = strlen(transform->filter->name);
1513    nparams = transform->nparams;
1514    return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
1515}
1516
1517static int
1518transform_filter_encode(ClientPtr client, char *output,
1519                        CARD16 *nbytesFilter,
1520                        CARD16 *nparamsFilter, RRTransformPtr transform)
1521{
1522    int nbytes, nparams;
1523
1524    if (transform->filter == NULL) {
1525        *nbytesFilter = 0;
1526        *nparamsFilter = 0;
1527        return 0;
1528    }
1529    nbytes = strlen(transform->filter->name);
1530    nparams = transform->nparams;
1531    *nbytesFilter = nbytes;
1532    *nparamsFilter = nparams;
1533    memcpy(output, transform->filter->name, nbytes);
1534    while ((nbytes & 3) != 0)
1535        output[nbytes++] = 0;
1536    memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
1537    if (client->swapped) {
1538        swaps(nbytesFilter);
1539        swaps(nparamsFilter);
1540        SwapLongs((CARD32 *) (output + nbytes), nparams);
1541    }
1542    nbytes += nparams * sizeof(xFixed);
1543    return nbytes;
1544}
1545
1546static void
1547transform_encode(ClientPtr client, xRenderTransform * wire,
1548                 PictTransform * pict)
1549{
1550    xRenderTransform_from_PictTransform(wire, pict);
1551    if (client->swapped)
1552        SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1553}
1554
1555int
1556ProcRRGetCrtcTransform(ClientPtr client)
1557{
1558    REQUEST(xRRGetCrtcTransformReq);
1559    xRRGetCrtcTransformReply *reply;
1560    RRCrtcPtr crtc;
1561    int nextra;
1562    RRTransformPtr current, pending;
1563    char *extra;
1564
1565    REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
1566    VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1567
1568    pending = &crtc->client_pending_transform;
1569    current = &crtc->client_current_transform;
1570
1571    nextra = (transform_filter_length(pending) +
1572              transform_filter_length(current));
1573
1574    reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
1575    if (!reply)
1576        return BadAlloc;
1577
1578    extra = (char *) (reply + 1);
1579    reply->type = X_Reply;
1580    reply->sequenceNumber = client->sequence;
1581    reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1582
1583    reply->hasTransforms = crtc->transforms;
1584
1585    transform_encode(client, &reply->pendingTransform, &pending->transform);
1586    extra += transform_filter_encode(client, extra,
1587                                     &reply->pendingNbytesFilter,
1588                                     &reply->pendingNparamsFilter, pending);
1589
1590    transform_encode(client, &reply->currentTransform, &current->transform);
1591    extra += transform_filter_encode(client, extra,
1592                                     &reply->currentNbytesFilter,
1593                                     &reply->currentNparamsFilter, current);
1594
1595    if (client->swapped) {
1596        swaps(&reply->sequenceNumber);
1597        swapl(&reply->length);
1598    }
1599    WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
1600    free(reply);
1601    return Success;
1602}
1603
1604static Bool
1605check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
1606{
1607    rrScrPriv(pScreen);
1608    int i;
1609    for (i = 0; i < pScrPriv->numCrtcs; i++) {
1610        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1611
1612        int left, right, top, bottom;
1613
1614        if (!crtc->mode)
1615            continue;
1616
1617        crtc_bounds(crtc, &left, &right, &top, &bottom);
1618
1619        if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
1620            return TRUE;
1621    }
1622    return FALSE;
1623}
1624
1625static Bool
1626constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
1627{
1628    rrScrPriv(pScreen);
1629    int i;
1630
1631    /* if we're trying to escape, clamp to the CRTC we're coming from */
1632    for (i = 0; i < pScrPriv->numCrtcs; i++) {
1633        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1634        int nx, ny;
1635        int left, right, top, bottom;
1636
1637        if (!crtc->mode)
1638            continue;
1639
1640        crtc_bounds(crtc, &left, &right, &top, &bottom);
1641        miPointerGetPosition(pDev, &nx, &ny);
1642
1643        if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
1644            if (*x < left)
1645                *x = left;
1646            if (*x >= right)
1647                *x = right - 1;
1648            if (*y < top)
1649                *y = top;
1650            if (*y >= bottom)
1651                *y = bottom - 1;
1652
1653            return TRUE;
1654        }
1655    }
1656    return FALSE;
1657}
1658
1659void
1660RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
1661                        int *y)
1662{
1663    rrScrPriv(pScreen);
1664    Bool ret;
1665    ScreenPtr slave;
1666
1667    /* intentional dead space -> let it float */
1668    if (pScrPriv->discontiguous)
1669        return;
1670
1671    /* if we're moving inside a crtc, we're fine */
1672    ret = check_all_screen_crtcs(pScreen, x, y);
1673    if (ret == TRUE)
1674        return;
1675
1676    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
1677        ret = check_all_screen_crtcs(slave, x, y);
1678        if (ret == TRUE)
1679            return;
1680    }
1681
1682    /* if we're trying to escape, clamp to the CRTC we're coming from */
1683    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
1684    if (ret == TRUE)
1685        return;
1686
1687    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
1688        ret = constrain_all_screen_crtcs(pDev, slave, x, y);
1689        if (ret == TRUE)
1690            return;
1691    }
1692}
1693
1694Bool
1695RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
1696{
1697    rrScrPriv(pDrawable->pScreen);
1698    Bool ret = TRUE;
1699    PixmapPtr *saved_scanout_pixmap;
1700    int i;
1701
1702    saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
1703    if (saved_scanout_pixmap == NULL)
1704        return FALSE;
1705
1706    for (i = 0; i < pScrPriv->numCrtcs; i++) {
1707        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1708        Bool size_fits;
1709
1710        saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1711
1712        if (!crtc->mode && enable)
1713            continue;
1714        if (!crtc->scanout_pixmap && !enable)
1715            continue;
1716
1717        size_fits = (crtc->mode &&
1718                     crtc->x == pDrawable->x &&
1719                     crtc->y == pDrawable->y &&
1720                     crtc->mode->mode.width == pDrawable->width &&
1721                     crtc->mode->mode.height == pDrawable->height);
1722
1723        /* is the pixmap already set? */
1724        if (crtc->scanout_pixmap == pPixmap) {
1725            /* if its a disable then don't care about size */
1726            if (enable == FALSE) {
1727                /* set scanout to NULL */
1728                crtc->scanout_pixmap = NULL;
1729            }
1730            else if (!size_fits) {
1731                /* if the size no longer fits then drop off */
1732                crtc->scanout_pixmap = NULL;
1733                pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
1734
1735                (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
1736                                        crtc->rotation, crtc->numOutputs, crtc->outputs);
1737                saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1738                ret = FALSE;
1739            }
1740            else {
1741                /* if the size fits then we are already setup */
1742            }
1743        }
1744        else {
1745            if (!size_fits)
1746                ret = FALSE;
1747            else if (enable)
1748                crtc->scanout_pixmap = pPixmap;
1749            else
1750                /* reject an attempt to disable someone else's scanout_pixmap */
1751                ret = FALSE;
1752        }
1753    }
1754
1755    for (i = 0; i < pScrPriv->numCrtcs; i++) {
1756        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1757
1758        if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
1759            continue;
1760
1761        if (ret) {
1762            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
1763
1764            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
1765                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
1766        }
1767        else
1768            crtc->scanout_pixmap = saved_scanout_pixmap[i];
1769    }
1770    free(saved_scanout_pixmap);
1771
1772    return ret;
1773}
1774