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