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