2 * Copyright © 2006 Keith Packard
3 * Copyright 2010 Red Hat, Inc
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.
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
26 #include "mipointer.h"
31 * Notify the CRTC of some change
34 RRCrtcChanged(RRCrtcPtr crtc
, Bool layoutChanged
)
36 ScreenPtr pScreen
= crtc
->pScreen
;
42 RRSetChanged(pScreen
);
44 * Send ConfigureNotify on any layout change
47 pScrPriv
->layoutChanged
= TRUE
;
55 RRCrtcCreate(ScreenPtr pScreen
, void *devPrivate
)
59 rrScrPrivPtr pScrPriv
;
64 pScrPriv
= rrGetScrPriv(pScreen
);
66 /* make space for the crtc pointer */
67 if (pScrPriv
->numCrtcs
)
68 crtcs
= realloc(pScrPriv
->crtcs
,
69 (pScrPriv
->numCrtcs
+ 1) * sizeof(RRCrtcPtr
));
71 crtcs
= malloc(sizeof(RRCrtcPtr
));
74 pScrPriv
->crtcs
= crtcs
;
76 crtc
= calloc(1, sizeof(RRCrtcRec
));
79 crtc
->id
= FakeClientID(0);
80 crtc
->pScreen
= pScreen
;
84 crtc
->rotation
= RR_Rotate_0
;
85 crtc
->rotations
= RR_Rotate_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
);
98 if (!AddResource(crtc
->id
, RRCrtcType
, (pointer
) crtc
))
101 /* attach the screen and crtc together */
102 crtc
->pScreen
= pScreen
;
103 pScrPriv
->crtcs
[pScrPriv
->numCrtcs
++] = crtc
;
105 RRResourcesChanged(pScreen
);
111 * Set the allowed rotations on a CRTC
114 RRCrtcSetRotations(RRCrtcPtr crtc
, Rotation rotations
)
116 crtc
->rotations
= rotations
;
120 * Set whether transforms are allowed on a CRTC
123 RRCrtcSetTransformSupport(RRCrtcPtr crtc
, Bool transforms
)
125 crtc
->transforms
= transforms
;
129 * Notify the extension that the Crtc has been reconfigured,
130 * the driver calls this whenever it has updated the mode
133 RRCrtcNotify(RRCrtcPtr crtc
,
138 RRTransformPtr transform
, int numOutputs
, RROutputPtr
* outputs
)
143 * Check to see if any of the new outputs were
144 * not in the old list and mark them as changed
146 for (i
= 0; i
< numOutputs
; i
++) {
147 for (j
= 0; j
< crtc
->numOutputs
; j
++)
148 if (outputs
[i
] == crtc
->outputs
[j
])
150 if (j
== crtc
->numOutputs
) {
151 outputs
[i
]->crtc
= crtc
;
152 RROutputChanged(outputs
[i
], FALSE
);
153 RRCrtcChanged(crtc
, FALSE
);
157 * Check to see if any of the old outputs are
158 * not in the new list and mark them as changed
160 for (j
= 0; j
< crtc
->numOutputs
; j
++) {
161 for (i
= 0; i
< numOutputs
; i
++)
162 if (outputs
[i
] == crtc
->outputs
[j
])
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
);
172 * Reallocate the crtc output array if necessary
174 if (numOutputs
!= crtc
->numOutputs
) {
175 RROutputPtr
*newoutputs
;
178 if (crtc
->numOutputs
)
179 newoutputs
= realloc(crtc
->outputs
,
180 numOutputs
* sizeof(RROutputPtr
));
182 newoutputs
= malloc(numOutputs
* sizeof(RROutputPtr
));
190 crtc
->outputs
= newoutputs
;
191 crtc
->numOutputs
= numOutputs
;
194 * Copy the new list of outputs into the crtc
196 memcpy(crtc
->outputs
, outputs
, numOutputs
* sizeof(RROutputPtr
));
198 * Update remaining crtc fields
200 if (mode
!= crtc
->mode
) {
202 RRModeDestroy(crtc
->mode
);
206 RRCrtcChanged(crtc
, TRUE
);
210 RRCrtcChanged(crtc
, TRUE
);
214 RRCrtcChanged(crtc
, TRUE
);
216 if (rotation
!= crtc
->rotation
) {
217 crtc
->rotation
= rotation
;
218 RRCrtcChanged(crtc
, TRUE
);
220 if (!RRTransformEqual(transform
, &crtc
->client_current_transform
)) {
221 RRTransformCopy(&crtc
->client_current_transform
, transform
);
222 RRCrtcChanged(crtc
, TRUE
);
224 if (crtc
->changed
&& mode
) {
225 RRTransformCompute(x
, y
,
226 mode
->mode
.width
, mode
->mode
.height
,
228 &crtc
->client_current_transform
,
229 &crtc
->transform
, &crtc
->f_transform
,
236 RRDeliverCrtcEvent(ClientPtr client
, WindowPtr pWin
, RRCrtcPtr crtc
)
238 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
241 RRModePtr mode
= crtc
->mode
;
243 xRRCrtcChangeNotifyEvent ce
= {
244 .type
= RRNotify
+ RREventBase
,
245 .subCode
= RRNotify_CrtcChange
,
246 .timestamp
= pScrPriv
->lastSetTime
.milliseconds
,
247 .window
= pWin
->drawable
.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
256 WriteEventsToClient(client
, 1, (xEvent
*) &ce
);
260 RRCrtcPendingProperties(RRCrtcPtr crtc
)
262 ScreenPtr pScreen
= crtc
->pScreen
;
267 for (o
= 0; o
< pScrPriv
->numOutputs
; o
++) {
268 RROutputPtr output
= pScrPriv
->outputs
[o
];
270 if (output
->crtc
== crtc
&& output
->pendingProperties
)
277 crtc_bounds(RRCrtcPtr crtc
, int *left
, int *right
, int *top
, int *bottom
)
282 switch (crtc
->rotation
) {
286 *right
= crtc
->x
+ crtc
->mode
->mode
.width
;
287 *bottom
= crtc
->y
+ crtc
->mode
->mode
.height
;
291 *right
= crtc
->x
+ crtc
->mode
->mode
.height
;
292 *bottom
= crtc
->y
+ crtc
->mode
->mode
.width
;
297 /* overlapping counts as adjacent */
299 crtcs_adjacent(const RRCrtcPtr a
, const RRCrtcPtr b
)
301 /* left, right, top, bottom... */
304 int cl
, cr
, ct
, cb
; /* the overlap, if any */
306 crtc_bounds(a
, &al
, &ar
, &at
, &ab
);
307 crtc_bounds(b
, &bl
, &br
, &bt
, &bb
);
314 return (cl
<= cr
) && (ct
<= cb
);
317 /* Depth-first search and mark all CRTCs reachable from cur */
319 mark_crtcs(rrScrPrivPtr pScrPriv
, int *reachable
, int cur
)
323 reachable
[cur
] = TRUE
;
324 for (i
= 0; i
< pScrPriv
->numCrtcs
; ++i
) {
325 if (reachable
[i
] || !pScrPriv
->crtcs
[i
]->mode
)
327 if (crtcs_adjacent(pScrPriv
->crtcs
[cur
], pScrPriv
->crtcs
[i
]))
328 mark_crtcs(pScrPriv
, reachable
, i
);
333 RRComputeContiguity(ScreenPtr pScreen
)
336 Bool discontiguous
= TRUE
;
337 int i
, n
= pScrPriv
->numCrtcs
;
339 int *reachable
= calloc(n
, sizeof(int));
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
);
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
])
357 discontiguous
= FALSE
;
361 pScrPriv
->discontiguous
= discontiguous
;
365 RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc
)
367 ScreenPtr master
= crtc
->pScreen
->current_master
;
368 PixmapPtr mscreenpix
;
369 rrScrPriv(crtc
->pScreen
);
371 mscreenpix
= master
->GetScreenPixmap(master
);
373 pScrPriv
->rrCrtcSetScanoutPixmap(crtc
, NULL
);
374 if (crtc
->scanout_pixmap
) {
375 master
->StopPixmapTracking(mscreenpix
, crtc
->scanout_pixmap
);
377 * Unref the pixmap twice: once for the original reference, and once
378 * for the reference implicitly added by PixmapShareToSlave.
380 master
->DestroyPixmap(crtc
->scanout_pixmap
->master_pixmap
);
381 master
->DestroyPixmap(crtc
->scanout_pixmap
->master_pixmap
);
382 crtc
->pScreen
->DestroyPixmap(crtc
->scanout_pixmap
);
384 crtc
->scanout_pixmap
= NULL
;
385 RRCrtcChanged(crtc
, TRUE
);
389 rrCreateSharedPixmap(RRCrtcPtr crtc
, int width
, int height
,
392 PixmapPtr mpix
, spix
;
393 ScreenPtr master
= crtc
->pScreen
->current_master
;
396 PixmapPtr mscreenpix
;
397 PixmapPtr protopix
= crtc
->pScreen
->current_master
->GetScreenPixmap(crtc
->pScreen
->current_master
);
398 rrScrPriv(crtc
->pScreen
);
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
408 mscreenpix
= master
->GetScreenPixmap(master
);
409 depth
= protopix
->drawable
.depth
;
411 if (crtc
->scanout_pixmap
)
412 RRCrtcDetachScanoutPixmap(crtc
);
414 if (width
== 0 && height
== 0) {
418 mpix
= master
->CreatePixmap(master
, width
, height
, depth
,
419 CREATE_PIXMAP_USAGE_SHARED
);
423 spix
= PixmapShareToSlave(mpix
, crtc
->pScreen
);
425 master
->DestroyPixmap(mpix
);
429 ret
= pScrPriv
->rrCrtcSetScanoutPixmap(crtc
, spix
);
431 ErrorF("failed to set shadow slave pixmap\n");
435 crtc
->scanout_pixmap
= spix
;
437 master
->StartPixmapTracking(mscreenpix
, spix
, x
, y
);
442 rrCheckPixmapBounding(ScreenPtr pScreen
,
443 RRCrtcPtr rr_crtc
, int x
, int y
, int w
, int h
)
445 RegionRec root_pixmap_region
, total_region
, new_crtc_region
;
450 int new_width
, new_height
;
451 PixmapPtr screen_pixmap
= pScreen
->GetScreenPixmap(pScreen
);
454 PixmapRegionInit(&root_pixmap_region
, screen_pixmap
);
455 RegionInit(&total_region
, NULL
, 0);
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
) {
466 if (!pScrPriv
->crtcs
[c
]->mode
)
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
;
473 RegionInit(&new_crtc_region
, &newbox
, 1);
474 RegionUnion(&total_region
, &total_region
, &new_crtc_region
);
477 xorg_list_for_each_entry(slave
, &pScreen
->output_slave_list
, output_head
) {
479 for (c
= 0; c
< pScrPriv
->numCrtcs
; c
++)
480 if (pScrPriv
->crtcs
[c
] == rr_crtc
) {
487 if (!pScrPriv
->crtcs
[c
]->mode
)
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
;
494 RegionInit(&new_crtc_region
, &newbox
, 1);
495 RegionUnion(&total_region
, &total_region
, &new_crtc_region
);
498 newsize
= RegionExtents(&total_region
);
499 new_width
= newsize
->x2
- newsize
->x1
;
500 new_height
= newsize
->y2
- newsize
->y1
;
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
);
507 pScrPriv
->rrScreenSetSize(pScreen
, new_width
, new_height
, 0, 0);
510 /* set shatters TODO */
515 * Request that the Crtc be reconfigured
518 RRCrtcSet(RRCrtcPtr crtc
,
521 int y
, Rotation rotation
, int numOutputs
, RROutputPtr
* outputs
)
523 ScreenPtr pScreen
= crtc
->pScreen
;
525 Bool recompute
= TRUE
;
529 /* See if nothing changed */
530 if (crtc
->mode
== mode
&&
533 crtc
->rotation
== rotation
&&
534 crtc
->numOutputs
== numOutputs
&&
535 !memcmp(crtc
->outputs
, outputs
, numOutputs
* sizeof(RROutputPtr
)) &&
536 !RRCrtcPendingProperties(crtc
) && !RRCrtcPendingTransform(crtc
)) {
541 if (pScreen
->isGPU
) {
542 ScreenPtr master
= pScreen
->current_master
;
543 int width
= 0, height
= 0;
546 width
= mode
->mode
.width
;
547 height
= mode
->mode
.height
;
549 ErrorF("have a master to look out for\n");
550 ret
= rrCheckPixmapBounding(master
, crtc
,
551 x
, y
, width
, height
);
555 if (pScreen
->current_master
) {
556 ret
= rrCreateSharedPixmap(crtc
, width
, height
, x
, y
);
557 ErrorF("need to create shared pixmap %d", ret
);
561 #if RANDR_12_INTERFACE
562 if (pScrPriv
->rrCrtcSet
) {
563 ret
= (*pScrPriv
->rrCrtcSet
) (pScreen
, crtc
, mode
, x
, y
,
564 rotation
, numOutputs
, outputs
);
569 #if RANDR_10_INTERFACE
570 if (pScrPriv
->rrSetConfig
) {
575 RRCrtcNotify(crtc
, NULL
, x
, y
, rotation
, NULL
, 0, NULL
);
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
;
586 size
.mmWidth
= pScreen
->mmWidth
;
587 size
.mmHeight
= pScreen
->mmHeight
;
590 rate
.rate
= RRVerticalRefresh(&mode
->mode
);
593 (*pScrPriv
->rrSetConfig
) (pScreen
, rotation
, rate
.rate
,
596 * Old 1.0 interface tied screen size to mode size
599 RRCrtcNotify(crtc
, mode
, x
, y
, rotation
, NULL
, 1,
601 RRScreenSizeNotify(pScreen
);
610 RRTellChanged(pScreen
);
612 for (o
= 0; o
< numOutputs
; o
++)
613 RRPostPendingProperties(outputs
[o
]);
618 RRComputeContiguity(pScreen
);
624 * Return crtc transform
627 RRCrtcGetTransform(RRCrtcPtr crtc
)
629 RRTransformPtr transform
= &crtc
->client_pending_transform
;
631 if (pixman_transform_is_identity(&transform
->transform
))
637 * Check whether the pending and current transforms are the same
640 RRCrtcPendingTransform(RRCrtcPtr crtc
)
642 return memcmp(&crtc
->client_current_transform
.transform
,
643 &crtc
->client_pending_transform
.transform
,
644 sizeof(PictTransform
)) != 0;
648 * Destroy a Crtc at shutdown
651 RRCrtcDestroy(RRCrtcPtr crtc
)
653 FreeResource(crtc
->id
, 0);
657 RRCrtcDestroyResource(pointer value
, XID pid
)
659 RRCrtcPtr crtc
= (RRCrtcPtr
) value
;
660 ScreenPtr pScreen
= crtc
->pScreen
;
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
;
675 RRResourcesChanged(pScreen
);
678 if (crtc
->scanout_pixmap
)
679 RRCrtcDetachScanoutPixmap(crtc
);
680 free(crtc
->gammaRed
);
682 RRModeDestroy(crtc
->mode
);
688 * Request that the Crtc gamma be changed
692 RRCrtcGammaSet(RRCrtcPtr crtc
, CARD16
*red
, CARD16
*green
, CARD16
*blue
)
696 #if RANDR_12_INTERFACE
697 ScreenPtr pScreen
= crtc
->pScreen
;
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
706 if (pScrPriv
->rrCrtcSetGamma
)
707 ret
= (*pScrPriv
->rrCrtcSetGamma
) (pScreen
, crtc
);
714 * Request current gamma back from the DDX (if possible).
715 * This includes gamma size.
718 RRCrtcGammaGet(RRCrtcPtr crtc
)
722 #if RANDR_12_INTERFACE
723 ScreenPtr pScreen
= crtc
->pScreen
;
726 #if RANDR_12_INTERFACE
729 if (pScrPriv
->rrCrtcGetGamma
)
730 ret
= (*pScrPriv
->rrCrtcGetGamma
) (pScreen
, crtc
);
737 * Notify the extension that the Crtc gamma has been changed
738 * The driver calls this whenever it has changed the gamma values
743 RRCrtcGammaNotify(RRCrtcPtr crtc
)
745 return TRUE
; /* not much going on here */
749 RRModeGetScanoutSize(RRModePtr mode
, PictTransformPtr transform
,
750 int *width
, int *height
)
762 box
.x2
= mode
->mode
.width
;
763 box
.y2
= mode
->mode
.height
;
765 pixman_transform_bounds(transform
, &box
);
766 *width
= box
.x2
- box
.x1
;
767 *height
= box
.y2
- box
.y1
;
771 * Returns the width/height that the crtc scans out from the framebuffer
774 RRCrtcGetScanoutSize(RRCrtcPtr crtc
, int *width
, int *height
)
776 RRModeGetScanoutSize(crtc
->mode
, &crtc
->transform
, width
, height
);
780 * Set the size of the gamma table at server startup time
784 RRCrtcGammaSetSize(RRCrtcPtr crtc
, int size
)
788 if (size
== crtc
->gammaSize
)
791 gamma
= malloc(size
* 3 * sizeof(CARD16
));
797 free(crtc
->gammaRed
);
798 crtc
->gammaRed
= gamma
;
799 crtc
->gammaGreen
= gamma
+ size
;
800 crtc
->gammaBlue
= gamma
+ size
* 2;
801 crtc
->gammaSize
= size
;
806 * Set the pending CRTC transformation
810 RRCrtcTransformSet(RRCrtcPtr crtc
,
811 PictTransformPtr transform
,
812 struct pixman_f_transform
*f_transform
,
813 struct pixman_f_transform
*f_inverse
,
815 int filter_len
, xFixed
* params
, int nparams
)
817 PictFilterPtr filter
= NULL
;
818 int width
= 0, height
= 0;
820 if (!crtc
->transforms
)
824 filter
= PictureFindFilter(crtc
->pScreen
, filter_name
, filter_len
);
827 if (filter
->ValidateParams
) {
828 if (!filter
->ValidateParams(crtc
->pScreen
, filter
->id
,
829 params
, nparams
, &width
, &height
))
833 width
= filter
->width
;
834 height
= filter
->height
;
841 if (!RRTransformSetFilter(&crtc
->client_pending_transform
,
842 filter
, params
, nparams
, width
, height
))
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
;
852 * Initialize crtc type
857 RRCrtcType
= CreateNewResourceType(RRCrtcDestroyResource
, "CRTC");
865 * Initialize crtc type error value
868 RRCrtcInitErrorValue(void)
870 SetResourceTypeErrorValue(RRCrtcType
, RRErrorBase
+ BadRRCrtc
);
874 ProcRRGetCrtcInfo(ClientPtr client
)
876 REQUEST(xRRGetCrtcInfoReq
);
877 xRRGetCrtcInfoReply rep
;
880 unsigned long extraLen
;
882 rrScrPrivPtr pScrPriv
;
890 REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq
);
891 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
893 /* All crtcs must be associated with screens before client
894 * requests are processed
896 pScreen
= crtc
->pScreen
;
897 pScrPriv
= rrGetScrPriv(pScreen
);
901 rep
= (xRRGetCrtcInfoReply
) {
903 .status
= RRSetConfigSuccess
,
904 .sequenceNumber
= client
->sequence
,
906 .timestamp
= pScrPriv
->lastSetTime
.milliseconds
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
))
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
;
918 RRCrtcGetScanoutSize(crtc
, &width
, &height
);
924 rep
.mode
= mode
? mode
->mode
.id
: 0;
925 rep
.rotation
= crtc
->rotation
;
926 rep
.rotations
= crtc
->rotations
;
927 rep
.nOutput
= crtc
->numOutputs
;
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
)
933 rep
.nPossibleOutput
= k
;
935 rep
.length
= rep
.nOutput
+ rep
.nPossibleOutput
;
937 extraLen
= rep
.length
<< 2;
939 extra
= malloc(extraLen
);
946 outputs
= (RROutput
*) extra
;
947 possible
= (RROutput
*) (outputs
+ rep
.nOutput
);
949 for (i
= 0; i
< crtc
->numOutputs
; i
++) {
950 outputs
[i
] = crtc
->outputs
[i
]->id
;
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
;
964 if (client
->swapped
) {
965 swaps(&rep
.sequenceNumber
);
967 swapl(&rep
.timestamp
);
973 swaps(&rep
.rotation
);
974 swaps(&rep
.rotations
);
976 swaps(&rep
.nPossibleOutput
);
978 WriteToClient(client
, sizeof(xRRGetCrtcInfoReply
), &rep
);
980 WriteToClient(client
, extraLen
, extra
);
988 ProcRRSetCrtcConfig(ClientPtr client
)
990 REQUEST(xRRSetCrtcConfigReq
);
991 xRRSetCrtcConfigReply rep
;
993 rrScrPrivPtr pScrPriv
;
997 RROutputPtr
*outputs
= NULL
;
1004 REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq
);
1005 numOutputs
= (stuff
->length
- bytes_to_int32(SIZEOF(xRRSetCrtcConfigReq
)));
1007 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixSetAttrAccess
);
1009 if (stuff
->mode
== None
) {
1015 VERIFY_RR_MODE(stuff
->mode
, mode
, DixSetAttrAccess
);
1016 if (numOutputs
== 0)
1020 outputs
= malloc(numOutputs
* sizeof(RROutputPtr
));
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
) {
1035 /* validate crtc for this output */
1036 for (j
= 0; j
< outputs
[i
]->numCrtcs
; j
++)
1037 if (outputs
[i
]->crtcs
[j
] == crtc
)
1039 if (j
== outputs
[i
]->numCrtcs
) {
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
]);
1051 if (j
== outputs
[i
]->numModes
+ outputs
[i
]->numUserModes
) {
1056 /* validate clones */
1057 for (i
= 0; i
< numOutputs
; i
++) {
1058 for (j
= 0; j
< numOutputs
; j
++) {
1063 for (k
= 0; k
< outputs
[i
]->numClones
; k
++) {
1064 if (outputs
[i
]->clones
[k
] == outputs
[j
])
1067 if (k
== outputs
[i
]->numClones
) {
1074 pScreen
= crtc
->pScreen
;
1075 pScrPriv
= rrGetScrPriv(pScreen
);
1077 time
= ClientTimeToServerTime(stuff
->timestamp
);
1081 status
= RRSetConfigFailed
;
1086 * Validate requested rotation
1088 rotation
= (Rotation
) stuff
->rotation
;
1090 /* test the rotation bits only! */
1091 switch (rotation
& 0xf) {
1101 client
->errorValue
= stuff
->rotation
;
1107 if ((~crtc
->rotations
) & rotation
) {
1109 * requested rotation or reflection not supported by screen
1111 client
->errorValue
= stuff
->rotation
;
1116 #ifdef RANDR_12_INTERFACE
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.
1124 if (pScrPriv
->rrScreenSetSize
&& !crtc
->transforms
) {
1127 PictTransform transform
;
1128 struct pixman_f_transform f_transform
, f_inverse
;
1131 if (pScreen
->isGPU
) {
1132 width
= pScreen
->current_master
->width
;
1133 height
= pScreen
->current_master
->height
;
1136 width
= pScreen
->width
;
1137 height
= pScreen
->height
;
1140 RRTransformCompute(stuff
->x
, stuff
->y
,
1141 mode
->mode
.width
, mode
->mode
.height
,
1143 &crtc
->client_pending_transform
,
1144 &transform
, &f_transform
, &f_inverse
);
1146 RRModeGetScanoutSize(mode
, &transform
, &source_width
,
1148 if (stuff
->x
+ source_width
> width
) {
1149 client
->errorValue
= stuff
->x
;
1154 if (stuff
->y
+ source_height
> height
) {
1155 client
->errorValue
= stuff
->y
;
1163 if (!RRCrtcSet(crtc
, mode
, stuff
->x
, stuff
->y
,
1164 rotation
, numOutputs
, outputs
)) {
1165 status
= RRSetConfigFailed
;
1168 status
= RRSetConfigSuccess
;
1169 pScrPriv
->lastSetTime
= time
;
1174 rep
= (xRRSetCrtcConfigReply
) {
1177 .sequenceNumber
= client
->sequence
,
1179 .newTimestamp
= pScrPriv
->lastSetTime
.milliseconds
1182 if (client
->swapped
) {
1183 swaps(&rep
.sequenceNumber
);
1185 swapl(&rep
.newTimestamp
);
1187 WriteToClient(client
, sizeof(xRRSetCrtcConfigReply
), &rep
);
1193 ProcRRGetPanning(ClientPtr client
)
1195 REQUEST(xRRGetPanningReq
);
1196 xRRGetPanningReply rep
;
1199 rrScrPrivPtr pScrPriv
;
1204 REQUEST_SIZE_MATCH(xRRGetPanningReq
);
1205 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1207 /* All crtcs must be associated with screens before client
1208 * requests are processed
1210 pScreen
= crtc
->pScreen
;
1211 pScrPriv
= rrGetScrPriv(pScreen
);
1214 return RRErrorBase
+ BadRRCrtc
;
1216 rep
= (xRRGetPanningReply
) {
1218 .status
= RRSetConfigSuccess
,
1219 .sequenceNumber
= client
->sequence
,
1221 .timestamp
= pScrPriv
->lastSetTime
.milliseconds
1224 if (pScrPriv
->rrGetPanning
&&
1225 pScrPriv
->rrGetPanning(pScreen
, crtc
, &total
, &tracking
, border
)) {
1226 rep
.left
= total
.x1
;
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];
1240 if (client
->swapped
) {
1241 swaps(&rep
.sequenceNumber
);
1243 swapl(&rep
.timestamp
);
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
);
1257 WriteToClient(client
, sizeof(xRRGetPanningReply
), &rep
);
1262 ProcRRSetPanning(ClientPtr client
)
1264 REQUEST(xRRSetPanningReq
);
1265 xRRSetPanningReply rep
;
1268 rrScrPrivPtr pScrPriv
;
1275 REQUEST_SIZE_MATCH(xRRSetPanningReq
);
1276 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1278 /* All crtcs must be associated with screens before client
1279 * requests are processed
1281 pScreen
= crtc
->pScreen
;
1282 pScrPriv
= rrGetScrPriv(pScreen
);
1286 status
= RRSetConfigFailed
;
1290 time
= ClientTimeToServerTime(stuff
->timestamp
);
1292 if (!pScrPriv
->rrGetPanning
)
1293 return RRErrorBase
+ BadRRCrtc
;
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
;
1308 if (!pScrPriv
->rrSetPanning(pScreen
, crtc
, &total
, &tracking
, border
))
1311 pScrPriv
->lastSetTime
= time
;
1313 status
= RRSetConfigSuccess
;
1316 rep
= (xRRSetPanningReply
) {
1319 .sequenceNumber
= client
->sequence
,
1321 .newTimestamp
= pScrPriv
->lastSetTime
.milliseconds
1324 if (client
->swapped
) {
1325 swaps(&rep
.sequenceNumber
);
1327 swapl(&rep
.newTimestamp
);
1329 WriteToClient(client
, sizeof(xRRSetPanningReply
), &rep
);
1334 ProcRRGetCrtcGammaSize(ClientPtr client
)
1336 REQUEST(xRRGetCrtcGammaSizeReq
);
1337 xRRGetCrtcGammaSizeReply reply
;
1340 REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq
);
1341 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1343 /* Gamma retrieval failed, any better error? */
1344 if (!RRCrtcGammaGet(crtc
))
1345 return RRErrorBase
+ BadRRCrtc
;
1347 reply
= (xRRGetCrtcGammaSizeReply
) {
1349 .sequenceNumber
= client
->sequence
,
1351 .size
= crtc
->gammaSize
1353 if (client
->swapped
) {
1354 swaps(&reply
.sequenceNumber
);
1355 swapl(&reply
.length
);
1358 WriteToClient(client
, sizeof(xRRGetCrtcGammaSizeReply
), &reply
);
1363 ProcRRGetCrtcGamma(ClientPtr client
)
1365 REQUEST(xRRGetCrtcGammaReq
);
1366 xRRGetCrtcGammaReply reply
;
1371 REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq
);
1372 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1374 /* Gamma retrieval failed, any better error? */
1375 if (!RRCrtcGammaGet(crtc
))
1376 return RRErrorBase
+ BadRRCrtc
;
1378 len
= crtc
->gammaSize
* 3 * 2;
1380 if (crtc
->gammaSize
) {
1381 extra
= malloc(len
);
1386 reply
= (xRRGetCrtcGammaReply
) {
1388 .sequenceNumber
= client
->sequence
,
1389 .length
= bytes_to_int32(len
),
1390 .size
= crtc
->gammaSize
1392 if (client
->swapped
) {
1393 swaps(&reply
.sequenceNumber
);
1394 swapl(&reply
.length
);
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
);
1408 ProcRRSetCrtcGamma(ClientPtr client
)
1410 REQUEST(xRRSetCrtcGammaReq
);
1413 CARD16
*red
, *green
, *blue
;
1415 REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq
);
1416 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1418 len
= client
->req_len
- bytes_to_int32(sizeof(xRRSetCrtcGammaReq
));
1419 if (len
< (stuff
->size
* 3 + 1) >> 1)
1422 if (stuff
->size
!= crtc
->gammaSize
)
1425 red
= (CARD16
*) (stuff
+ 1);
1426 green
= red
+ crtc
->gammaSize
;
1427 blue
= green
+ crtc
->gammaSize
;
1429 RRCrtcGammaSet(crtc
, red
, green
, blue
);
1434 /* Version 1.3 additions */
1437 ProcRRSetCrtcTransform(ClientPtr client
)
1439 REQUEST(xRRSetCrtcTransformReq
);
1441 PictTransform transform
;
1442 struct pixman_f_transform f_transform
, f_inverse
;
1448 REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq
);
1449 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
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
))
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
;
1463 return RRCrtcTransformSet(crtc
, &transform
, &f_transform
, &f_inverse
,
1464 filter
, nbytes
, params
, nparams
);
1467 #define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
1470 transform_filter_length(RRTransformPtr transform
)
1472 int nbytes
, nparams
;
1474 if (transform
->filter
== NULL
)
1476 nbytes
= strlen(transform
->filter
->name
);
1477 nparams
= transform
->nparams
;
1478 return pad_to_int32(nbytes
) + (nparams
* sizeof(xFixed
));
1482 transform_filter_encode(ClientPtr client
, char *output
,
1483 CARD16
*nbytesFilter
,
1484 CARD16
*nparamsFilter
, RRTransformPtr transform
)
1486 int nbytes
, nparams
;
1488 if (transform
->filter
== NULL
) {
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
);
1506 nbytes
+= nparams
* sizeof(xFixed
);
1511 transform_encode(ClientPtr client
, xRenderTransform
* wire
,
1512 PictTransform
* pict
)
1514 xRenderTransform_from_PictTransform(wire
, pict
);
1515 if (client
->swapped
)
1516 SwapLongs((CARD32
*) wire
, bytes_to_int32(sizeof(xRenderTransform
)));
1520 ProcRRGetCrtcTransform(ClientPtr client
)
1522 REQUEST(xRRGetCrtcTransformReq
);
1523 xRRGetCrtcTransformReply
*reply
;
1526 RRTransformPtr current
, pending
;
1529 REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq
);
1530 VERIFY_RR_CRTC(stuff
->crtc
, crtc
, DixReadAccess
);
1532 pending
= &crtc
->client_pending_transform
;
1533 current
= &crtc
->client_current_transform
;
1535 nextra
= (transform_filter_length(pending
) +
1536 transform_filter_length(current
));
1538 reply
= calloc(1, sizeof(xRRGetCrtcTransformReply
) + nextra
);
1542 extra
= (char *) (reply
+ 1);
1543 reply
->type
= X_Reply
;
1544 reply
->sequenceNumber
= client
->sequence
;
1545 reply
->length
= bytes_to_int32(CrtcTransformExtra
+ nextra
);
1547 reply
->hasTransforms
= crtc
->transforms
;
1549 transform_encode(client
, &reply
->pendingTransform
, &pending
->transform
);
1550 extra
+= transform_filter_encode(client
, extra
,
1551 &reply
->pendingNbytesFilter
,
1552 &reply
->pendingNparamsFilter
, pending
);
1554 transform_encode(client
, &reply
->currentTransform
, ¤t
->transform
);
1555 extra
+= transform_filter_encode(client
, extra
,
1556 &reply
->currentNbytesFilter
,
1557 &reply
->currentNparamsFilter
, current
);
1559 if (client
->swapped
) {
1560 swaps(&reply
->sequenceNumber
);
1561 swapl(&reply
->length
);
1563 WriteToClient(client
, sizeof(xRRGetCrtcTransformReply
) + nextra
, reply
);
1568 static Bool
check_all_screen_crtcs(ScreenPtr pScreen
, int *x
, int *y
)
1572 for (i
= 0; i
< pScrPriv
->numCrtcs
; i
++) {
1573 RRCrtcPtr crtc
= pScrPriv
->crtcs
[i
];
1575 int left
, right
, top
, bottom
;
1580 crtc_bounds(crtc
, &left
, &right
, &top
, &bottom
);
1582 if ((*x
>= left
) && (*x
< right
) && (*y
>= top
) && (*y
< bottom
))
1588 static Bool
constrain_all_screen_crtcs(DeviceIntPtr pDev
, ScreenPtr pScreen
, int *x
, int *y
)
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
];
1597 int left
, right
, top
, bottom
;
1602 crtc_bounds(crtc
, &left
, &right
, &top
, &bottom
);
1603 miPointerGetPosition(pDev
, &nx
, &ny
);
1605 if ((nx
>= left
) && (nx
< right
) && (ny
>= top
) && (ny
< bottom
)) {
1622 RRConstrainCursorHarder(DeviceIntPtr pDev
, ScreenPtr pScreen
, int mode
, int *x
,
1629 /* intentional dead space -> let it float */
1630 if (pScrPriv
->discontiguous
)
1633 /* if we're moving inside a crtc, we're fine */
1634 ret
= check_all_screen_crtcs(pScreen
, x
, y
);
1638 xorg_list_for_each_entry(slave
, &pScreen
->output_slave_list
, output_head
) {
1639 ret
= check_all_screen_crtcs(slave
, x
, y
);
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
);
1649 xorg_list_for_each_entry(slave
, &pScreen
->output_slave_list
, output_head
) {
1650 ret
= constrain_all_screen_crtcs(pDev
, slave
, x
, y
);
1657 RRReplaceScanoutPixmap(DrawablePtr pDrawable
, PixmapPtr pPixmap
, Bool enable
)
1659 rrScrPriv(pDrawable
->pScreen
);
1661 Bool size_fits
= FALSE
;
1662 Bool changed
= FALSE
;
1665 for (i
= 0; i
< pScrPriv
->numCrtcs
; i
++) {
1666 RRCrtcPtr crtc
= pScrPriv
->crtcs
[i
];
1668 if (!crtc
->mode
&& enable
)
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
)
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
;
1686 /* if the size fits then we are already setup */
1689 /* if the size no longer fits then drop off */
1690 crtc
->scanout_pixmap
= NULL
;
1698 crtc
->scanout_pixmap
= pPixmap
;
1699 pScrPriv
->rrCrtcSetScanoutPixmap(crtc
, pPixmap
);
1704 if (changed
&& pScrPriv
->rrCrtcSet
) {
1705 pScrPriv
->rrCrtcSetScanoutPixmap(crtc
, crtc
->scanout_pixmap
);
1707 (*pScrPriv
->rrCrtcSet
) (pDrawable
->pScreen
, crtc
, crtc
->mode
, crtc
->x
, crtc
->y
,
1708 crtc
->rotation
, crtc
->numOutputs
, crtc
->outputs
);