xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/modes/xf86Rotate.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2006 Keith Packard
3  * Copyright © 2011 Aaron Plattner
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 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
26 #endif
27 
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include "mi.h"
32 #include "xf86.h"
33 #include "xf86DDC.h"
34 #include "windowstr.h"
35 #include "xf86Crtc.h"
36 #include "xf86Modes.h"
37 #include "xf86RandR12.h"
38 #include "X11/extensions/render.h"
39 #include "X11/extensions/dpmsconst.h"
40 #include "X11/Xatom.h"
41 
42 static void
xf86RotateCrtcRedisplay(xf86CrtcPtr crtc,RegionPtr region)43 xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
44 {
45     ScrnInfoPtr scrn = crtc->scrn;
46     ScreenPtr screen = scrn->pScreen;
47     WindowPtr root = screen->root;
48     PixmapPtr dst_pixmap = crtc->rotatedPixmap;
49     PictFormatPtr format = PictureWindowFormat(screen->root);
50     int error;
51     PicturePtr src, dst;
52     int n = RegionNumRects(region);
53     BoxPtr b = RegionRects(region);
54     XID include_inferiors = IncludeInferiors;
55 
56     if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput)
57         return;
58 
59     src = CreatePicture(None,
60                         &root->drawable,
61                         format,
62                         CPSubwindowMode,
63                         &include_inferiors, serverClient, &error);
64     if (!src)
65         return;
66 
67     dst = CreatePicture(None,
68                         &dst_pixmap->drawable,
69                         format, 0L, NULL, serverClient, &error);
70     if (!dst)
71         return;
72 
73     error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
74     if (error)
75         return;
76     if (crtc->transform_in_use && crtc->filter)
77         SetPicturePictFilter(src, crtc->filter, crtc->params, crtc->nparams);
78 
79     if (crtc->shadowClear) {
80         CompositePicture(PictOpSrc,
81                          src, NULL, dst,
82                          0, 0, 0, 0, 0, 0,
83                          crtc->mode.HDisplay, crtc->mode.VDisplay);
84         crtc->shadowClear = FALSE;
85     }
86     else {
87         while (n--) {
88             BoxRec dst_box;
89 
90             dst_box = *b;
91             dst_box.x1 -= crtc->filter_width >> 1;
92             dst_box.x2 += crtc->filter_width >> 1;
93             dst_box.y1 -= crtc->filter_height >> 1;
94             dst_box.y2 += crtc->filter_height >> 1;
95             pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &dst_box);
96             CompositePicture(PictOpSrc,
97                              src, NULL, dst,
98                              dst_box.x1, dst_box.y1, 0, 0, dst_box.x1,
99                              dst_box.y1, dst_box.x2 - dst_box.x1,
100                              dst_box.y2 - dst_box.y1);
101             b++;
102         }
103     }
104     FreePicture(src, None);
105     FreePicture(dst, None);
106 }
107 
108 static void
xf86CrtcDamageShadow(xf86CrtcPtr crtc)109 xf86CrtcDamageShadow(xf86CrtcPtr crtc)
110 {
111     ScrnInfoPtr pScrn = crtc->scrn;
112     BoxRec damage_box;
113     RegionRec damage_region;
114     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
115 
116     damage_box.x1 = 0;
117     damage_box.x2 = crtc->mode.HDisplay;
118     damage_box.y1 = 0;
119     damage_box.y2 = crtc->mode.VDisplay;
120     if (!pixman_transform_bounds(&crtc->crtc_to_framebuffer, &damage_box)) {
121         damage_box.x1 = 0;
122         damage_box.y1 = 0;
123         damage_box.x2 = pScreen->width;
124         damage_box.y2 = pScreen->height;
125     }
126     if (damage_box.x1 < 0)
127         damage_box.x1 = 0;
128     if (damage_box.y1 < 0)
129         damage_box.y1 = 0;
130     if (damage_box.x2 > pScreen->width)
131         damage_box.x2 = pScreen->width;
132     if (damage_box.y2 > pScreen->height)
133         damage_box.y2 = pScreen->height;
134     RegionInit(&damage_region, &damage_box, 1);
135     DamageDamageRegion(&(*pScreen->GetScreenPixmap) (pScreen)->drawable,
136                        &damage_region);
137     RegionUninit(&damage_region);
138     crtc->shadowClear = TRUE;
139 }
140 
141 static void
xf86RotatePrepare(ScreenPtr pScreen)142 xf86RotatePrepare(ScreenPtr pScreen)
143 {
144     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
145     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
146     int c;
147 
148     for (c = 0; c < xf86_config->num_crtc; c++) {
149         xf86CrtcPtr crtc = xf86_config->crtc[c];
150 
151         if (crtc->rotatedData && !crtc->rotatedPixmap) {
152             crtc->rotatedPixmap = crtc->funcs->shadow_create(crtc,
153                                                              crtc->rotatedData,
154                                                              crtc->mode.
155                                                              HDisplay,
156                                                              crtc->mode.
157                                                              VDisplay);
158             if (!xf86_config->rotation_damage_registered) {
159                 /* Hook damage to screen pixmap */
160                 DamageRegister(&pScreen->root->drawable,
161                                xf86_config->rotation_damage);
162                 xf86_config->rotation_damage_registered = TRUE;
163                 EnableLimitedSchedulingLatency();
164             }
165 
166             xf86CrtcDamageShadow(crtc);
167         }
168     }
169 }
170 
171 static Bool
xf86RotateRedisplay(ScreenPtr pScreen)172 xf86RotateRedisplay(ScreenPtr pScreen)
173 {
174     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
175     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
176     DamagePtr damage = xf86_config->rotation_damage;
177     RegionPtr region;
178 
179     if (!damage || !pScreen->root)
180         return FALSE;
181     xf86RotatePrepare(pScreen);
182     region = DamageRegion(damage);
183     if (RegionNotEmpty(region)) {
184         int c;
185         SourceValidateProcPtr SourceValidate;
186 
187         /*
188          * SourceValidate is used by the software cursor code
189          * to pull the cursor off of the screen when reading
190          * bits from the frame buffer. Bypassing this function
191          * leaves the software cursor in place
192          */
193         SourceValidate = pScreen->SourceValidate;
194         pScreen->SourceValidate = miSourceValidate;
195 
196         for (c = 0; c < xf86_config->num_crtc; c++) {
197             xf86CrtcPtr crtc = xf86_config->crtc[c];
198 
199             if (crtc->transform_in_use && crtc->enabled) {
200                 RegionRec crtc_damage;
201 
202                 /* compute portion of damage that overlaps crtc */
203                 RegionInit(&crtc_damage, &crtc->bounds, 1);
204                 RegionIntersect(&crtc_damage, &crtc_damage, region);
205 
206                 /* update damaged region */
207                 if (RegionNotEmpty(&crtc_damage))
208                     xf86RotateCrtcRedisplay(crtc, &crtc_damage);
209 
210                 RegionUninit(&crtc_damage);
211             }
212         }
213         pScreen->SourceValidate = SourceValidate;
214         DamageEmpty(damage);
215     }
216     return TRUE;
217 }
218 
219 static void
xf86RotateBlockHandler(ScreenPtr pScreen,void * pTimeout)220 xf86RotateBlockHandler(ScreenPtr pScreen, void *pTimeout)
221 {
222     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
223     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
224 
225     /* Unwrap before redisplay in case the software
226      * cursor layer wants to add its block handler to the
227      * chain
228      */
229     pScreen->BlockHandler = xf86_config->BlockHandler;
230 
231     xf86RotateRedisplay(pScreen);
232 
233     (*pScreen->BlockHandler) (pScreen, pTimeout);
234 
235     /* Re-wrap if we still need this hook */
236     if (xf86_config->rotation_damage != NULL) {
237         xf86_config->BlockHandler = pScreen->BlockHandler;
238         pScreen->BlockHandler = xf86RotateBlockHandler;
239     } else
240         xf86_config->BlockHandler = NULL;
241 }
242 
243 void
xf86RotateDestroy(xf86CrtcPtr crtc)244 xf86RotateDestroy(xf86CrtcPtr crtc)
245 {
246     ScrnInfoPtr pScrn = crtc->scrn;
247     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
248     int c;
249 
250     /* Free memory from rotation */
251     if (crtc->rotatedPixmap || crtc->rotatedData) {
252         crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
253                                     crtc->rotatedData);
254         crtc->rotatedPixmap = NULL;
255         crtc->rotatedData = NULL;
256     }
257 
258     for (c = 0; c < xf86_config->num_crtc; c++)
259         if (xf86_config->crtc[c]->rotatedData)
260             return;
261 
262     /*
263      * Clean up damage structures when no crtcs are rotated
264      */
265     if (xf86_config->rotation_damage) {
266         /* Free damage structure */
267         if (xf86_config->rotation_damage_registered) {
268             xf86_config->rotation_damage_registered = FALSE;
269             DisableLimitedSchedulingLatency();
270         }
271         DamageDestroy(xf86_config->rotation_damage);
272         xf86_config->rotation_damage = NULL;
273     }
274 }
275 
276 void
xf86RotateFreeShadow(ScrnInfoPtr pScrn)277 xf86RotateFreeShadow(ScrnInfoPtr pScrn)
278 {
279     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
280     int c;
281 
282     for (c = 0; c < config->num_crtc; c++) {
283         xf86CrtcPtr crtc = config->crtc[c];
284 
285         if (crtc->rotatedPixmap || crtc->rotatedData) {
286             crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
287                                         crtc->rotatedData);
288             crtc->rotatedPixmap = NULL;
289             crtc->rotatedData = NULL;
290         }
291     }
292 }
293 
294 void
xf86RotateCloseScreen(ScreenPtr screen)295 xf86RotateCloseScreen(ScreenPtr screen)
296 {
297     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
298     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
299     int c;
300 
301     if (xf86_config->rotation_damage) {
302         if (xf86_config->rotation_damage_registered) {
303             /*
304              * This has already been destroyed when the root window
305              * was destroyed
306              */
307             xf86_config->rotation_damage_registered = FALSE;
308         } else {
309             /* Free damage structure */
310             DamageDestroy(xf86_config->rotation_damage);
311         }
312         xf86_config->rotation_damage = NULL;
313     }
314 
315     for (c = 0; c < xf86_config->num_crtc; c++)
316         xf86RotateDestroy(xf86_config->crtc[c]);
317 }
318 
319 static Bool
xf86CrtcFitsScreen(xf86CrtcPtr crtc,struct pict_f_transform * crtc_to_fb)320 xf86CrtcFitsScreen(xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb)
321 {
322     ScrnInfoPtr pScrn = crtc->scrn;
323     BoxRec b;
324 
325     /* When called before PreInit, the driver is
326      * presumably doing load detect
327      */
328     if (pScrn->is_gpu) {
329 	ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
330 	if (pScreen->current_master)
331 	    pScrn = xf86ScreenToScrn(pScreen->current_master);
332     }
333 
334     if (pScrn->virtualX == 0 || pScrn->virtualY == 0)
335         return TRUE;
336 
337     b.x1 = 0;
338     b.y1 = 0;
339     b.x2 = crtc->mode.HDisplay;
340     b.y2 = crtc->mode.VDisplay;
341     if (crtc_to_fb)
342         pixman_f_transform_bounds(crtc_to_fb, &b);
343     else {
344         b.x1 += crtc->x;
345         b.y1 += crtc->y;
346         b.x2 += crtc->x;
347         b.y2 += crtc->y;
348     }
349 
350     return (0 <= b.x1 && b.x2 <= pScrn->virtualX &&
351             0 <= b.y1 && b.y2 <= pScrn->virtualY);
352 }
353 
354 Bool
xf86CrtcRotate(xf86CrtcPtr crtc)355 xf86CrtcRotate(xf86CrtcPtr crtc)
356 {
357     ScrnInfoPtr pScrn = crtc->scrn;
358     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
359     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
360     PictTransform crtc_to_fb;
361     struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
362     xFixed *new_params = NULL;
363     int new_nparams = 0;
364     PictFilterPtr new_filter = NULL;
365     int new_width = 0;
366     int new_height = 0;
367     RRTransformPtr transform = NULL;
368     Bool damage = FALSE;
369 
370     if (pScreen->isGPU)
371         return TRUE;
372     if (crtc->transformPresent)
373         transform = &crtc->transform;
374 
375     if (!RRTransformCompute(crtc->x, crtc->y,
376                             crtc->mode.HDisplay, crtc->mode.VDisplay,
377                             crtc->rotation,
378                             transform,
379                             &crtc_to_fb,
380                             &f_crtc_to_fb,
381                             &f_fb_to_crtc) &&
382         xf86CrtcFitsScreen(crtc, &f_crtc_to_fb)) {
383         /*
384          * If the untranslated transformation is the identity,
385          * disable the shadow buffer
386          */
387         xf86RotateDestroy(crtc);
388         crtc->transform_in_use = FALSE;
389         free(new_params);
390         new_params = NULL;
391         new_nparams = 0;
392         new_filter = NULL;
393         new_width = 0;
394         new_height = 0;
395     }
396     else {
397         if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput) {
398             xf86RotateDestroy(crtc);
399         }
400         else {
401             /*
402              * these are the size of the shadow pixmap, which
403              * matches the mode, not the pre-rotated copy in the
404              * frame buffer
405              */
406             int width = crtc->mode.HDisplay;
407             int height = crtc->mode.VDisplay;
408             void *shadowData = crtc->rotatedData;
409             PixmapPtr shadow = crtc->rotatedPixmap;
410             int old_width = shadow ? shadow->drawable.width : 0;
411             int old_height = shadow ? shadow->drawable.height : 0;
412 
413             /* Allocate memory for rotation */
414             if (old_width != width || old_height != height) {
415                 if (shadow || shadowData) {
416                     crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
417                     crtc->rotatedPixmap = NULL;
418                     crtc->rotatedData = NULL;
419                 }
420                 shadowData = crtc->funcs->shadow_allocate(crtc, width, height);
421                 if (!shadowData)
422                     goto bail1;
423                 crtc->rotatedData = shadowData;
424                 /* shadow will be damaged in xf86RotatePrepare */
425             }
426             else {
427                 /* mark shadowed area as damaged so it will be repainted */
428                 damage = TRUE;
429             }
430 
431             if (!xf86_config->rotation_damage) {
432                 /* Create damage structure */
433                 xf86_config->rotation_damage = DamageCreate(NULL, NULL,
434                                                             DamageReportNone,
435                                                             TRUE, pScreen,
436                                                             pScreen);
437                 if (!xf86_config->rotation_damage)
438                     goto bail2;
439 
440                 /* Wrap block handler */
441                 if (!xf86_config->BlockHandler) {
442                     xf86_config->BlockHandler = pScreen->BlockHandler;
443                     pScreen->BlockHandler = xf86RotateBlockHandler;
444                 }
445             }
446 
447             if (0) {
448  bail2:
449                 if (shadow || shadowData) {
450                     crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
451                     crtc->rotatedPixmap = NULL;
452                     crtc->rotatedData = NULL;
453                 }
454  bail1:
455                 if (old_width && old_height)
456                     crtc->rotatedPixmap =
457                         crtc->funcs->shadow_create(crtc, NULL, old_width,
458                                                    old_height);
459                 return FALSE;
460             }
461         }
462 #ifdef RANDR_12_INTERFACE
463         if (transform) {
464             if (transform->nparams) {
465                 new_params = malloc(transform->nparams * sizeof(xFixed));
466                 if (new_params) {
467                     memcpy(new_params, transform->params,
468                            transform->nparams * sizeof(xFixed));
469                     new_nparams = transform->nparams;
470                     new_filter = transform->filter;
471                 }
472             }
473             else
474                 new_filter = transform->filter;
475             if (new_filter) {
476                 new_width = new_filter->width;
477                 new_height = new_filter->height;
478             }
479         }
480 #endif
481         crtc->transform_in_use = TRUE;
482     }
483     crtc->crtc_to_framebuffer = crtc_to_fb;
484     crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
485     crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
486     free(crtc->params);
487     crtc->params = new_params;
488     crtc->nparams = new_nparams;
489     crtc->filter = new_filter;
490     crtc->filter_width = new_width;
491     crtc->filter_height = new_height;
492     crtc->bounds.x1 = 0;
493     crtc->bounds.x2 = crtc->mode.HDisplay;
494     crtc->bounds.y1 = 0;
495     crtc->bounds.y2 = crtc->mode.VDisplay;
496     pixman_f_transform_bounds(&f_crtc_to_fb, &crtc->bounds);
497 
498     if (damage)
499         xf86CrtcDamageShadow(crtc);
500     else if (crtc->rotatedData && !crtc->rotatedPixmap)
501         /* Make sure the new rotate buffer has valid transformed contents */
502         xf86RotateRedisplay(pScreen);
503 
504     /* All done */
505     return TRUE;
506 }
507