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 = 0;
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
RRCrtcInScreen(ScreenPtr pScreen,RRCrtcPtr findCrtc)963 static Bool RRCrtcInScreen(ScreenPtr pScreen, RRCrtcPtr findCrtc)
964 {
965 rrScrPrivPtr pScrPriv;
966 int c;
967
968 if (pScreen == NULL)
969 return FALSE;
970
971 if (findCrtc == NULL)
972 return FALSE;
973
974 if (!dixPrivateKeyRegistered(rrPrivKey))
975 return FALSE;
976
977 pScrPriv = rrGetScrPriv(pScreen);
978 for (c = 0; c < pScrPriv->numCrtcs; c++) {
979 if (pScrPriv->crtcs[c] == findCrtc)
980 return TRUE;
981 }
982
983 return FALSE;
984 }
985
RRCrtcExists(ScreenPtr pScreen,RRCrtcPtr findCrtc)986 Bool RRCrtcExists(ScreenPtr pScreen, RRCrtcPtr findCrtc)
987 {
988 ScreenPtr slave= NULL;
989
990 if (RRCrtcInScreen(pScreen, findCrtc))
991 return TRUE;
992
993 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
994 if (!slave->is_output_slave)
995 continue;
996 if (RRCrtcInScreen(slave, findCrtc))
997 return TRUE;
998 }
999
1000 return FALSE;
1001 }
1002
1003
1004 /*
1005 * Notify the extension that the Crtc gamma has been changed
1006 * The driver calls this whenever it has changed the gamma values
1007 * in the RRCrtcRec
1008 */
1009
1010 Bool
RRCrtcGammaNotify(RRCrtcPtr crtc)1011 RRCrtcGammaNotify(RRCrtcPtr crtc)
1012 {
1013 return TRUE; /* not much going on here */
1014 }
1015
1016 static void
RRModeGetScanoutSize(RRModePtr mode,PictTransformPtr transform,int * width,int * height)1017 RRModeGetScanoutSize(RRModePtr mode, PictTransformPtr transform,
1018 int *width, int *height)
1019 {
1020 BoxRec box;
1021
1022 if (mode == NULL) {
1023 *width = 0;
1024 *height = 0;
1025 return;
1026 }
1027
1028 box.x1 = 0;
1029 box.y1 = 0;
1030 box.x2 = mode->mode.width;
1031 box.y2 = mode->mode.height;
1032
1033 pixman_transform_bounds(transform, &box);
1034 *width = box.x2 - box.x1;
1035 *height = box.y2 - box.y1;
1036 }
1037
1038 /**
1039 * Returns the width/height that the crtc scans out from the framebuffer
1040 */
1041 void
RRCrtcGetScanoutSize(RRCrtcPtr crtc,int * width,int * height)1042 RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
1043 {
1044 RRModeGetScanoutSize(crtc->mode, &crtc->transform, width, height);
1045 }
1046
1047 /*
1048 * Set the size of the gamma table at server startup time
1049 */
1050
1051 Bool
RRCrtcGammaSetSize(RRCrtcPtr crtc,int size)1052 RRCrtcGammaSetSize(RRCrtcPtr crtc, int size)
1053 {
1054 CARD16 *gamma;
1055
1056 if (size == crtc->gammaSize)
1057 return TRUE;
1058 if (size) {
1059 gamma = xallocarray(size, 3 * sizeof(CARD16));
1060 if (!gamma)
1061 return FALSE;
1062 }
1063 else
1064 gamma = NULL;
1065 free(crtc->gammaRed);
1066 crtc->gammaRed = gamma;
1067 crtc->gammaGreen = gamma + size;
1068 crtc->gammaBlue = gamma + size * 2;
1069 crtc->gammaSize = size;
1070 return TRUE;
1071 }
1072
1073 /*
1074 * Set the pending CRTC transformation
1075 */
1076
1077 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)1078 RRCrtcTransformSet(RRCrtcPtr crtc,
1079 PictTransformPtr transform,
1080 struct pixman_f_transform *f_transform,
1081 struct pixman_f_transform *f_inverse,
1082 char *filter_name,
1083 int filter_len, xFixed * params, int nparams)
1084 {
1085 PictFilterPtr filter = NULL;
1086 int width = 0, height = 0;
1087
1088 if (!crtc->transforms)
1089 return BadValue;
1090
1091 if (filter_len) {
1092 filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
1093 if (!filter)
1094 return BadName;
1095 if (filter->ValidateParams) {
1096 if (!filter->ValidateParams(crtc->pScreen, filter->id,
1097 params, nparams, &width, &height))
1098 return BadMatch;
1099 }
1100 else {
1101 width = filter->width;
1102 height = filter->height;
1103 }
1104 }
1105 else {
1106 if (nparams)
1107 return BadMatch;
1108 }
1109 if (!RRTransformSetFilter(&crtc->client_pending_transform,
1110 filter, params, nparams, width, height))
1111 return BadAlloc;
1112
1113 crtc->client_pending_transform.transform = *transform;
1114 crtc->client_pending_transform.f_transform = *f_transform;
1115 crtc->client_pending_transform.f_inverse = *f_inverse;
1116 return Success;
1117 }
1118
1119 /*
1120 * Initialize crtc type
1121 */
1122 Bool
RRCrtcInit(void)1123 RRCrtcInit(void)
1124 {
1125 RRCrtcType = CreateNewResourceType(RRCrtcDestroyResource, "CRTC");
1126 if (!RRCrtcType)
1127 return FALSE;
1128
1129 return TRUE;
1130 }
1131
1132 /*
1133 * Initialize crtc type error value
1134 */
1135 void
RRCrtcInitErrorValue(void)1136 RRCrtcInitErrorValue(void)
1137 {
1138 SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
1139 }
1140
1141 int
ProcRRGetCrtcInfo(ClientPtr client)1142 ProcRRGetCrtcInfo(ClientPtr client)
1143 {
1144 REQUEST(xRRGetCrtcInfoReq);
1145 xRRGetCrtcInfoReply rep;
1146 RRCrtcPtr crtc;
1147 CARD8 *extra = NULL;
1148 unsigned long extraLen;
1149 ScreenPtr pScreen;
1150 rrScrPrivPtr pScrPriv;
1151 RRModePtr mode;
1152 RROutput *outputs;
1153 RROutput *possible;
1154 int i, j, k;
1155 int width, height;
1156 BoxRec panned_area;
1157 Bool leased;
1158
1159 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
1160 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1161
1162 leased = RRCrtcIsLeased(crtc);
1163
1164 /* All crtcs must be associated with screens before client
1165 * requests are processed
1166 */
1167 pScreen = crtc->pScreen;
1168 pScrPriv = rrGetScrPriv(pScreen);
1169
1170 mode = crtc->mode;
1171
1172 rep = (xRRGetCrtcInfoReply) {
1173 .type = X_Reply,
1174 .status = RRSetConfigSuccess,
1175 .sequenceNumber = client->sequence,
1176 .length = 0,
1177 .timestamp = pScrPriv->lastSetTime.milliseconds
1178 };
1179 if (leased) {
1180 rep.x = rep.y = rep.width = rep.height = 0;
1181 rep.mode = 0;
1182 rep.rotation = RR_Rotate_0;
1183 rep.rotations = RR_Rotate_0;
1184 rep.nOutput = 0;
1185 rep.nPossibleOutput = 0;
1186 rep.length = 0;
1187 extraLen = 0;
1188 } else {
1189 if (pScrPriv->rrGetPanning &&
1190 pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
1191 (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
1192 {
1193 rep.x = panned_area.x1;
1194 rep.y = panned_area.y1;
1195 rep.width = panned_area.x2 - panned_area.x1;
1196 rep.height = panned_area.y2 - panned_area.y1;
1197 }
1198 else {
1199 RRCrtcGetScanoutSize(crtc, &width, &height);
1200 rep.x = crtc->x;
1201 rep.y = crtc->y;
1202 rep.width = width;
1203 rep.height = height;
1204 }
1205 rep.mode = mode ? mode->mode.id : 0;
1206 rep.rotation = crtc->rotation;
1207 rep.rotations = crtc->rotations;
1208 rep.nOutput = crtc->numOutputs;
1209 k = 0;
1210 for (i = 0; i < pScrPriv->numOutputs; i++) {
1211 if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1212 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1213 if (pScrPriv->outputs[i]->crtcs[j] == crtc)
1214 k++;
1215 }
1216 }
1217
1218 rep.nPossibleOutput = k;
1219
1220 rep.length = rep.nOutput + rep.nPossibleOutput;
1221
1222 extraLen = rep.length << 2;
1223 if (extraLen) {
1224 extra = malloc(extraLen);
1225 if (!extra)
1226 return BadAlloc;
1227 }
1228
1229 outputs = (RROutput *) extra;
1230 possible = (RROutput *) (outputs + rep.nOutput);
1231
1232 for (i = 0; i < crtc->numOutputs; i++) {
1233 outputs[i] = crtc->outputs[i]->id;
1234 if (client->swapped)
1235 swapl(&outputs[i]);
1236 }
1237 k = 0;
1238 for (i = 0; i < pScrPriv->numOutputs; i++) {
1239 if (!RROutputIsLeased(pScrPriv->outputs[i])) {
1240 for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
1241 if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
1242 possible[k] = pScrPriv->outputs[i]->id;
1243 if (client->swapped)
1244 swapl(&possible[k]);
1245 k++;
1246 }
1247 }
1248 }
1249 }
1250
1251 if (client->swapped) {
1252 swaps(&rep.sequenceNumber);
1253 swapl(&rep.length);
1254 swapl(&rep.timestamp);
1255 swaps(&rep.x);
1256 swaps(&rep.y);
1257 swaps(&rep.width);
1258 swaps(&rep.height);
1259 swapl(&rep.mode);
1260 swaps(&rep.rotation);
1261 swaps(&rep.rotations);
1262 swaps(&rep.nOutput);
1263 swaps(&rep.nPossibleOutput);
1264 }
1265 WriteToClient(client, sizeof(xRRGetCrtcInfoReply), &rep);
1266 if (extraLen) {
1267 WriteToClient(client, extraLen, extra);
1268 free(extra);
1269 }
1270
1271 return Success;
1272 }
1273
1274 int
ProcRRSetCrtcConfig(ClientPtr client)1275 ProcRRSetCrtcConfig(ClientPtr client)
1276 {
1277 REQUEST(xRRSetCrtcConfigReq);
1278 xRRSetCrtcConfigReply rep;
1279 ScreenPtr pScreen;
1280 rrScrPrivPtr pScrPriv;
1281 RRCrtcPtr crtc;
1282 RRModePtr mode;
1283 int numOutputs;
1284 RROutputPtr *outputs = NULL;
1285 RROutput *outputIds;
1286 TimeStamp time;
1287 Rotation rotation;
1288 int ret, i, j;
1289 CARD8 status;
1290
1291 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
1292 numOutputs = (stuff->length - bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq)));
1293
1294 VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
1295
1296 if (RRCrtcIsLeased(crtc))
1297 return BadAccess;
1298
1299 if (stuff->mode == None) {
1300 mode = NULL;
1301 if (numOutputs > 0)
1302 return BadMatch;
1303 }
1304 else {
1305 VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
1306 if (numOutputs == 0)
1307 return BadMatch;
1308 }
1309 if (numOutputs) {
1310 outputs = xallocarray(numOutputs, sizeof(RROutputPtr));
1311 if (!outputs)
1312 return BadAlloc;
1313 }
1314 else
1315 outputs = NULL;
1316
1317 outputIds = (RROutput *) (stuff + 1);
1318 for (i = 0; i < numOutputs; i++) {
1319 ret = dixLookupResourceByType((void **) (outputs + i), outputIds[i],
1320 RROutputType, client, DixSetAttrAccess);
1321 if (ret != Success) {
1322 free(outputs);
1323 return ret;
1324 }
1325
1326 if (RROutputIsLeased(outputs[i])) {
1327 free(outputs);
1328 return BadAccess;
1329 }
1330
1331 /* validate crtc for this output */
1332 for (j = 0; j < outputs[i]->numCrtcs; j++)
1333 if (outputs[i]->crtcs[j] == crtc)
1334 break;
1335 if (j == outputs[i]->numCrtcs) {
1336 free(outputs);
1337 return BadMatch;
1338 }
1339 /* validate mode for this output */
1340 for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++) {
1341 RRModePtr m = (j < outputs[i]->numModes ?
1342 outputs[i]->modes[j] :
1343 outputs[i]->userModes[j - outputs[i]->numModes]);
1344 if (m == mode)
1345 break;
1346 }
1347 if (j == outputs[i]->numModes + outputs[i]->numUserModes) {
1348 free(outputs);
1349 return BadMatch;
1350 }
1351 }
1352 /* validate clones */
1353 for (i = 0; i < numOutputs; i++) {
1354 for (j = 0; j < numOutputs; j++) {
1355 int k;
1356
1357 if (i == j)
1358 continue;
1359 for (k = 0; k < outputs[i]->numClones; k++) {
1360 if (outputs[i]->clones[k] == outputs[j])
1361 break;
1362 }
1363 if (k == outputs[i]->numClones) {
1364 free(outputs);
1365 return BadMatch;
1366 }
1367 }
1368 }
1369
1370 pScreen = crtc->pScreen;
1371 pScrPriv = rrGetScrPriv(pScreen);
1372
1373 time = ClientTimeToServerTime(stuff->timestamp);
1374
1375 if (!pScrPriv) {
1376 time = currentTime;
1377 status = RRSetConfigFailed;
1378 goto sendReply;
1379 }
1380
1381 /*
1382 * Validate requested rotation
1383 */
1384 rotation = (Rotation) stuff->rotation;
1385
1386 /* test the rotation bits only! */
1387 switch (rotation & 0xf) {
1388 case RR_Rotate_0:
1389 case RR_Rotate_90:
1390 case RR_Rotate_180:
1391 case RR_Rotate_270:
1392 break;
1393 default:
1394 /*
1395 * Invalid rotation
1396 */
1397 client->errorValue = stuff->rotation;
1398 free(outputs);
1399 return BadValue;
1400 }
1401
1402 if (mode) {
1403 if ((~crtc->rotations) & rotation) {
1404 /*
1405 * requested rotation or reflection not supported by screen
1406 */
1407 client->errorValue = stuff->rotation;
1408 free(outputs);
1409 return BadMatch;
1410 }
1411
1412 #ifdef RANDR_12_INTERFACE
1413 /*
1414 * Check screen size bounds if the DDX provides a 1.2 interface
1415 * for setting screen size. Else, assume the CrtcSet sets
1416 * the size along with the mode. If the driver supports transforms,
1417 * then it must allow crtcs to display a subset of the screen, so
1418 * only do this check for drivers without transform support.
1419 */
1420 if (pScrPriv->rrScreenSetSize && !crtc->transforms) {
1421 int source_width;
1422 int source_height;
1423 PictTransform transform;
1424 struct pixman_f_transform f_transform, f_inverse;
1425 int width, height;
1426
1427 if (pScreen->isGPU) {
1428 width = pScreen->current_master->width;
1429 height = pScreen->current_master->height;
1430 }
1431 else {
1432 width = pScreen->width;
1433 height = pScreen->height;
1434 }
1435
1436 RRTransformCompute(stuff->x, stuff->y,
1437 mode->mode.width, mode->mode.height,
1438 rotation,
1439 &crtc->client_pending_transform,
1440 &transform, &f_transform, &f_inverse);
1441
1442 RRModeGetScanoutSize(mode, &transform, &source_width,
1443 &source_height);
1444 if (stuff->x + source_width > width) {
1445 client->errorValue = stuff->x;
1446 free(outputs);
1447 return BadValue;
1448 }
1449
1450 if (stuff->y + source_height > height) {
1451 client->errorValue = stuff->y;
1452 free(outputs);
1453 return BadValue;
1454 }
1455 }
1456 #endif
1457 }
1458
1459 if (!RRCrtcSet(crtc, mode, stuff->x, stuff->y,
1460 rotation, numOutputs, outputs)) {
1461 status = RRSetConfigFailed;
1462 goto sendReply;
1463 }
1464 status = RRSetConfigSuccess;
1465 pScrPriv->lastSetTime = time;
1466
1467 sendReply:
1468 free(outputs);
1469
1470 rep = (xRRSetCrtcConfigReply) {
1471 .type = X_Reply,
1472 .status = status,
1473 .sequenceNumber = client->sequence,
1474 .length = 0,
1475 .newTimestamp = pScrPriv->lastSetTime.milliseconds
1476 };
1477
1478 if (client->swapped) {
1479 swaps(&rep.sequenceNumber);
1480 swapl(&rep.length);
1481 swapl(&rep.newTimestamp);
1482 }
1483 WriteToClient(client, sizeof(xRRSetCrtcConfigReply), &rep);
1484
1485 return Success;
1486 }
1487
1488 int
ProcRRGetPanning(ClientPtr client)1489 ProcRRGetPanning(ClientPtr client)
1490 {
1491 REQUEST(xRRGetPanningReq);
1492 xRRGetPanningReply rep;
1493 RRCrtcPtr crtc;
1494 ScreenPtr pScreen;
1495 rrScrPrivPtr pScrPriv;
1496 BoxRec total;
1497 BoxRec tracking;
1498 INT16 border[4];
1499
1500 REQUEST_SIZE_MATCH(xRRGetPanningReq);
1501 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1502
1503 /* All crtcs must be associated with screens before client
1504 * requests are processed
1505 */
1506 pScreen = crtc->pScreen;
1507 pScrPriv = rrGetScrPriv(pScreen);
1508
1509 if (!pScrPriv)
1510 return RRErrorBase + BadRRCrtc;
1511
1512 rep = (xRRGetPanningReply) {
1513 .type = X_Reply,
1514 .status = RRSetConfigSuccess,
1515 .sequenceNumber = client->sequence,
1516 .length = 1,
1517 .timestamp = pScrPriv->lastSetTime.milliseconds
1518 };
1519
1520 if (pScrPriv->rrGetPanning &&
1521 pScrPriv->rrGetPanning(pScreen, crtc, &total, &tracking, border)) {
1522 rep.left = total.x1;
1523 rep.top = total.y1;
1524 rep.width = total.x2 - total.x1;
1525 rep.height = total.y2 - total.y1;
1526 rep.track_left = tracking.x1;
1527 rep.track_top = tracking.y1;
1528 rep.track_width = tracking.x2 - tracking.x1;
1529 rep.track_height = tracking.y2 - tracking.y1;
1530 rep.border_left = border[0];
1531 rep.border_top = border[1];
1532 rep.border_right = border[2];
1533 rep.border_bottom = border[3];
1534 }
1535
1536 if (client->swapped) {
1537 swaps(&rep.sequenceNumber);
1538 swapl(&rep.length);
1539 swapl(&rep.timestamp);
1540 swaps(&rep.left);
1541 swaps(&rep.top);
1542 swaps(&rep.width);
1543 swaps(&rep.height);
1544 swaps(&rep.track_left);
1545 swaps(&rep.track_top);
1546 swaps(&rep.track_width);
1547 swaps(&rep.track_height);
1548 swaps(&rep.border_left);
1549 swaps(&rep.border_top);
1550 swaps(&rep.border_right);
1551 swaps(&rep.border_bottom);
1552 }
1553 WriteToClient(client, sizeof(xRRGetPanningReply), &rep);
1554 return Success;
1555 }
1556
1557 int
ProcRRSetPanning(ClientPtr client)1558 ProcRRSetPanning(ClientPtr client)
1559 {
1560 REQUEST(xRRSetPanningReq);
1561 xRRSetPanningReply rep;
1562 RRCrtcPtr crtc;
1563 ScreenPtr pScreen;
1564 rrScrPrivPtr pScrPriv;
1565 TimeStamp time;
1566 BoxRec total;
1567 BoxRec tracking;
1568 INT16 border[4];
1569 CARD8 status;
1570
1571 REQUEST_SIZE_MATCH(xRRSetPanningReq);
1572 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1573
1574 if (RRCrtcIsLeased(crtc))
1575 return BadAccess;
1576
1577 /* All crtcs must be associated with screens before client
1578 * requests are processed
1579 */
1580 pScreen = crtc->pScreen;
1581 pScrPriv = rrGetScrPriv(pScreen);
1582
1583 if (!pScrPriv) {
1584 time = currentTime;
1585 status = RRSetConfigFailed;
1586 goto sendReply;
1587 }
1588
1589 time = ClientTimeToServerTime(stuff->timestamp);
1590
1591 if (!pScrPriv->rrGetPanning)
1592 return RRErrorBase + BadRRCrtc;
1593
1594 total.x1 = stuff->left;
1595 total.y1 = stuff->top;
1596 total.x2 = total.x1 + stuff->width;
1597 total.y2 = total.y1 + stuff->height;
1598 tracking.x1 = stuff->track_left;
1599 tracking.y1 = stuff->track_top;
1600 tracking.x2 = tracking.x1 + stuff->track_width;
1601 tracking.y2 = tracking.y1 + stuff->track_height;
1602 border[0] = stuff->border_left;
1603 border[1] = stuff->border_top;
1604 border[2] = stuff->border_right;
1605 border[3] = stuff->border_bottom;
1606
1607 if (!pScrPriv->rrSetPanning(pScreen, crtc, &total, &tracking, border))
1608 return BadMatch;
1609
1610 pScrPriv->lastSetTime = time;
1611
1612 status = RRSetConfigSuccess;
1613
1614 sendReply:
1615 rep = (xRRSetPanningReply) {
1616 .type = X_Reply,
1617 .status = status,
1618 .sequenceNumber = client->sequence,
1619 .length = 0,
1620 .newTimestamp = pScrPriv->lastSetTime.milliseconds
1621 };
1622
1623 if (client->swapped) {
1624 swaps(&rep.sequenceNumber);
1625 swapl(&rep.length);
1626 swapl(&rep.newTimestamp);
1627 }
1628 WriteToClient(client, sizeof(xRRSetPanningReply), &rep);
1629 return Success;
1630 }
1631
1632 int
ProcRRGetCrtcGammaSize(ClientPtr client)1633 ProcRRGetCrtcGammaSize(ClientPtr client)
1634 {
1635 REQUEST(xRRGetCrtcGammaSizeReq);
1636 xRRGetCrtcGammaSizeReply reply;
1637 RRCrtcPtr crtc;
1638
1639 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1640 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1641
1642 /* Gamma retrieval failed, any better error? */
1643 if (!RRCrtcGammaGet(crtc))
1644 return RRErrorBase + BadRRCrtc;
1645
1646 reply = (xRRGetCrtcGammaSizeReply) {
1647 .type = X_Reply,
1648 .sequenceNumber = client->sequence,
1649 .length = 0,
1650 .size = crtc->gammaSize
1651 };
1652 if (client->swapped) {
1653 swaps(&reply.sequenceNumber);
1654 swapl(&reply.length);
1655 swaps(&reply.size);
1656 }
1657 WriteToClient(client, sizeof(xRRGetCrtcGammaSizeReply), &reply);
1658 return Success;
1659 }
1660
1661 int
ProcRRGetCrtcGamma(ClientPtr client)1662 ProcRRGetCrtcGamma(ClientPtr client)
1663 {
1664 REQUEST(xRRGetCrtcGammaReq);
1665 xRRGetCrtcGammaReply reply;
1666 RRCrtcPtr crtc;
1667 unsigned long len;
1668 char *extra = NULL;
1669
1670 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1671 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1672
1673 /* Gamma retrieval failed, any better error? */
1674 if (!RRCrtcGammaGet(crtc))
1675 return RRErrorBase + BadRRCrtc;
1676
1677 len = crtc->gammaSize * 3 * 2;
1678
1679 if (crtc->gammaSize) {
1680 extra = malloc(len);
1681 if (!extra)
1682 return BadAlloc;
1683 }
1684
1685 reply = (xRRGetCrtcGammaReply) {
1686 .type = X_Reply,
1687 .sequenceNumber = client->sequence,
1688 .length = bytes_to_int32(len),
1689 .size = crtc->gammaSize
1690 };
1691 if (client->swapped) {
1692 swaps(&reply.sequenceNumber);
1693 swapl(&reply.length);
1694 swaps(&reply.size);
1695 }
1696 WriteToClient(client, sizeof(xRRGetCrtcGammaReply), &reply);
1697 if (crtc->gammaSize) {
1698 memcpy(extra, crtc->gammaRed, len);
1699 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
1700 WriteSwappedDataToClient(client, len, extra);
1701 free(extra);
1702 }
1703 return Success;
1704 }
1705
1706 int
ProcRRSetCrtcGamma(ClientPtr client)1707 ProcRRSetCrtcGamma(ClientPtr client)
1708 {
1709 REQUEST(xRRSetCrtcGammaReq);
1710 RRCrtcPtr crtc;
1711 unsigned long len;
1712 CARD16 *red, *green, *blue;
1713
1714 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1715 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1716
1717 if (RRCrtcIsLeased(crtc))
1718 return BadAccess;
1719
1720 len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
1721 if (len < (stuff->size * 3 + 1) >> 1)
1722 return BadLength;
1723
1724 if (stuff->size != crtc->gammaSize)
1725 return BadMatch;
1726
1727 red = (CARD16 *) (stuff + 1);
1728 green = red + crtc->gammaSize;
1729 blue = green + crtc->gammaSize;
1730
1731 RRCrtcGammaSet(crtc, red, green, blue);
1732
1733 return Success;
1734 }
1735
1736 /* Version 1.3 additions */
1737
1738 int
ProcRRSetCrtcTransform(ClientPtr client)1739 ProcRRSetCrtcTransform(ClientPtr client)
1740 {
1741 REQUEST(xRRSetCrtcTransformReq);
1742 RRCrtcPtr crtc;
1743 PictTransform transform;
1744 struct pixman_f_transform f_transform, f_inverse;
1745 char *filter;
1746 int nbytes;
1747 xFixed *params;
1748 int nparams;
1749
1750 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1751 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1752
1753 if (RRCrtcIsLeased(crtc))
1754 return BadAccess;
1755
1756 PictTransform_from_xRenderTransform(&transform, &stuff->transform);
1757 pixman_f_transform_from_pixman_transform(&f_transform, &transform);
1758 if (!pixman_f_transform_invert(&f_inverse, &f_transform))
1759 return BadMatch;
1760
1761 filter = (char *) (stuff + 1);
1762 nbytes = stuff->nbytesFilter;
1763 params = (xFixed *) (filter + pad_to_int32(nbytes));
1764 nparams = ((xFixed *) stuff + client->req_len) - params;
1765 if (nparams < 0)
1766 return BadLength;
1767
1768 return RRCrtcTransformSet(crtc, &transform, &f_transform, &f_inverse,
1769 filter, nbytes, params, nparams);
1770 }
1771
1772 #define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
1773
1774 static int
transform_filter_length(RRTransformPtr transform)1775 transform_filter_length(RRTransformPtr transform)
1776 {
1777 int nbytes, nparams;
1778
1779 if (transform->filter == NULL)
1780 return 0;
1781 nbytes = strlen(transform->filter->name);
1782 nparams = transform->nparams;
1783 return pad_to_int32(nbytes) + (nparams * sizeof(xFixed));
1784 }
1785
1786 static int
transform_filter_encode(ClientPtr client,char * output,CARD16 * nbytesFilter,CARD16 * nparamsFilter,RRTransformPtr transform)1787 transform_filter_encode(ClientPtr client, char *output,
1788 CARD16 *nbytesFilter,
1789 CARD16 *nparamsFilter, RRTransformPtr transform)
1790 {
1791 int nbytes, nparams;
1792
1793 if (transform->filter == NULL) {
1794 *nbytesFilter = 0;
1795 *nparamsFilter = 0;
1796 return 0;
1797 }
1798 nbytes = strlen(transform->filter->name);
1799 nparams = transform->nparams;
1800 *nbytesFilter = nbytes;
1801 *nparamsFilter = nparams;
1802 memcpy(output, transform->filter->name, nbytes);
1803 while ((nbytes & 3) != 0)
1804 output[nbytes++] = 0;
1805 memcpy(output + nbytes, transform->params, nparams * sizeof(xFixed));
1806 if (client->swapped) {
1807 swaps(nbytesFilter);
1808 swaps(nparamsFilter);
1809 SwapLongs((CARD32 *) (output + nbytes), nparams);
1810 }
1811 nbytes += nparams * sizeof(xFixed);
1812 return nbytes;
1813 }
1814
1815 static void
transform_encode(ClientPtr client,xRenderTransform * wire,PictTransform * pict)1816 transform_encode(ClientPtr client, xRenderTransform * wire,
1817 PictTransform * pict)
1818 {
1819 xRenderTransform_from_PictTransform(wire, pict);
1820 if (client->swapped)
1821 SwapLongs((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1822 }
1823
1824 int
ProcRRGetCrtcTransform(ClientPtr client)1825 ProcRRGetCrtcTransform(ClientPtr client)
1826 {
1827 REQUEST(xRRGetCrtcTransformReq);
1828 xRRGetCrtcTransformReply *reply;
1829 RRCrtcPtr crtc;
1830 int nextra;
1831 RRTransformPtr current, pending;
1832 char *extra;
1833
1834 REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
1835 VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1836
1837 pending = &crtc->client_pending_transform;
1838 current = &crtc->client_current_transform;
1839
1840 nextra = (transform_filter_length(pending) +
1841 transform_filter_length(current));
1842
1843 reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
1844 if (!reply)
1845 return BadAlloc;
1846
1847 extra = (char *) (reply + 1);
1848 reply->type = X_Reply;
1849 reply->sequenceNumber = client->sequence;
1850 reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1851
1852 reply->hasTransforms = crtc->transforms;
1853
1854 transform_encode(client, &reply->pendingTransform, &pending->transform);
1855 extra += transform_filter_encode(client, extra,
1856 &reply->pendingNbytesFilter,
1857 &reply->pendingNparamsFilter, pending);
1858
1859 transform_encode(client, &reply->currentTransform, ¤t->transform);
1860 extra += transform_filter_encode(client, extra,
1861 &reply->currentNbytesFilter,
1862 &reply->currentNparamsFilter, current);
1863
1864 if (client->swapped) {
1865 swaps(&reply->sequenceNumber);
1866 swapl(&reply->length);
1867 }
1868 WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
1869 free(reply);
1870 return Success;
1871 }
1872
1873 static Bool
check_all_screen_crtcs(ScreenPtr pScreen,int * x,int * y)1874 check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
1875 {
1876 rrScrPriv(pScreen);
1877 int i;
1878 for (i = 0; i < pScrPriv->numCrtcs; i++) {
1879 RRCrtcPtr crtc = pScrPriv->crtcs[i];
1880
1881 int left, right, top, bottom;
1882
1883 if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1884 continue;
1885
1886 if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
1887 return TRUE;
1888 }
1889 return FALSE;
1890 }
1891
1892 static Bool
constrain_all_screen_crtcs(DeviceIntPtr pDev,ScreenPtr pScreen,int * x,int * y)1893 constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
1894 {
1895 rrScrPriv(pScreen);
1896 int i;
1897
1898 /* if we're trying to escape, clamp to the CRTC we're coming from */
1899 for (i = 0; i < pScrPriv->numCrtcs; i++) {
1900 RRCrtcPtr crtc = pScrPriv->crtcs[i];
1901 int nx, ny;
1902 int left, right, top, bottom;
1903
1904 if (!cursor_bounds(crtc, &left, &right, &top, &bottom))
1905 continue;
1906
1907 miPointerGetPosition(pDev, &nx, &ny);
1908
1909 if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) {
1910 if (*x < left)
1911 *x = left;
1912 if (*x >= right)
1913 *x = right - 1;
1914 if (*y < top)
1915 *y = top;
1916 if (*y >= bottom)
1917 *y = bottom - 1;
1918
1919 return TRUE;
1920 }
1921 }
1922 return FALSE;
1923 }
1924
1925 void
RRConstrainCursorHarder(DeviceIntPtr pDev,ScreenPtr pScreen,int mode,int * x,int * y)1926 RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
1927 int *y)
1928 {
1929 rrScrPriv(pScreen);
1930 Bool ret;
1931 ScreenPtr slave;
1932
1933 /* intentional dead space -> let it float */
1934 if (pScrPriv->discontiguous)
1935 return;
1936
1937 /* if we're moving inside a crtc, we're fine */
1938 ret = check_all_screen_crtcs(pScreen, x, y);
1939 if (ret == TRUE)
1940 return;
1941
1942 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1943 if (!slave->is_output_slave)
1944 continue;
1945
1946 ret = check_all_screen_crtcs(slave, x, y);
1947 if (ret == TRUE)
1948 return;
1949 }
1950
1951 /* if we're trying to escape, clamp to the CRTC we're coming from */
1952 ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
1953 if (ret == TRUE)
1954 return;
1955
1956 xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) {
1957 if (!slave->is_output_slave)
1958 continue;
1959
1960 ret = constrain_all_screen_crtcs(pDev, slave, x, y);
1961 if (ret == TRUE)
1962 return;
1963 }
1964 }
1965
1966 Bool
RRReplaceScanoutPixmap(DrawablePtr pDrawable,PixmapPtr pPixmap,Bool enable)1967 RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
1968 {
1969 rrScrPriv(pDrawable->pScreen);
1970 Bool ret = TRUE;
1971 PixmapPtr *saved_scanout_pixmap;
1972 int i;
1973
1974 saved_scanout_pixmap = malloc(sizeof(PixmapPtr)*pScrPriv->numCrtcs);
1975 if (saved_scanout_pixmap == NULL)
1976 return FALSE;
1977
1978 for (i = 0; i < pScrPriv->numCrtcs; i++) {
1979 RRCrtcPtr crtc = pScrPriv->crtcs[i];
1980 Bool size_fits;
1981
1982 saved_scanout_pixmap[i] = crtc->scanout_pixmap;
1983
1984 if (!crtc->mode && enable)
1985 continue;
1986 if (!crtc->scanout_pixmap && !enable)
1987 continue;
1988
1989 /* not supported with double buffering, needs ABI change for 2 ppix */
1990 if (crtc->scanout_pixmap_back) {
1991 ret = FALSE;
1992 continue;
1993 }
1994
1995 size_fits = (crtc->mode &&
1996 crtc->x == pDrawable->x &&
1997 crtc->y == pDrawable->y &&
1998 crtc->mode->mode.width == pDrawable->width &&
1999 crtc->mode->mode.height == pDrawable->height);
2000
2001 /* is the pixmap already set? */
2002 if (crtc->scanout_pixmap == pPixmap) {
2003 /* if its a disable then don't care about size */
2004 if (enable == FALSE) {
2005 /* set scanout to NULL */
2006 crtc->scanout_pixmap = NULL;
2007 }
2008 else if (!size_fits) {
2009 /* if the size no longer fits then drop off */
2010 crtc->scanout_pixmap = NULL;
2011 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
2012
2013 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
2014 crtc->rotation, crtc->numOutputs, crtc->outputs);
2015 saved_scanout_pixmap[i] = crtc->scanout_pixmap;
2016 ret = FALSE;
2017 }
2018 else {
2019 /* if the size fits then we are already setup */
2020 }
2021 }
2022 else {
2023 if (!size_fits)
2024 ret = FALSE;
2025 else if (enable)
2026 crtc->scanout_pixmap = pPixmap;
2027 else
2028 /* reject an attempt to disable someone else's scanout_pixmap */
2029 ret = FALSE;
2030 }
2031 }
2032
2033 for (i = 0; i < pScrPriv->numCrtcs; i++) {
2034 RRCrtcPtr crtc = pScrPriv->crtcs[i];
2035
2036 if (crtc->scanout_pixmap == saved_scanout_pixmap[i])
2037 continue;
2038
2039 if (ret) {
2040 pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
2041
2042 (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
2043 crtc->rotation, crtc->numOutputs, crtc->outputs);
2044 }
2045 else
2046 crtc->scanout_pixmap = saved_scanout_pixmap[i];
2047 }
2048 free(saved_scanout_pixmap);
2049
2050 return ret;
2051 }
2052
2053 Bool
RRHasScanoutPixmap(ScreenPtr pScreen)2054 RRHasScanoutPixmap(ScreenPtr pScreen)
2055 {
2056 rrScrPrivPtr pScrPriv;
2057 int i;
2058
2059 /* Bail out if RandR wasn't initialized. */
2060 if (!dixPrivateKeyRegistered(rrPrivKey))
2061 return FALSE;
2062
2063 pScrPriv = rrGetScrPriv(pScreen);
2064
2065 if (!pScreen->is_output_slave)
2066 return FALSE;
2067
2068 for (i = 0; i < pScrPriv->numCrtcs; i++) {
2069 RRCrtcPtr crtc = pScrPriv->crtcs[i];
2070
2071 if (crtc->scanout_pixmap)
2072 return TRUE;
2073 }
2074
2075 return FALSE;
2076 }
2077