xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xf86Rotate.c (16554B)


      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
     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
    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
    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
    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
    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
    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
    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
    295 xf86RotateCloseScreen(ScreenPtr screen)
    296 {
    297     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    298     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    299     int c;
    300 
    301     /* This has already been destroyed when the root window was destroyed */
    302     xf86_config->rotation_damage = NULL;
    303     for (c = 0; c < xf86_config->num_crtc; c++)
    304         xf86RotateDestroy(xf86_config->crtc[c]);
    305 }
    306 
    307 static Bool
    308 xf86CrtcFitsScreen(xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb)
    309 {
    310     ScrnInfoPtr pScrn = crtc->scrn;
    311     BoxRec b;
    312 
    313     /* When called before PreInit, the driver is
    314      * presumably doing load detect
    315      */
    316     if (pScrn->is_gpu) {
    317 	ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
    318 	if (pScreen->current_primary)
    319 	    pScrn = xf86ScreenToScrn(pScreen->current_primary);
    320     }
    321 
    322     if (pScrn->virtualX == 0 || pScrn->virtualY == 0)
    323         return TRUE;
    324 
    325     b.x1 = 0;
    326     b.y1 = 0;
    327     b.x2 = crtc->mode.HDisplay;
    328     b.y2 = crtc->mode.VDisplay;
    329     if (crtc_to_fb)
    330         pixman_f_transform_bounds(crtc_to_fb, &b);
    331     else {
    332         b.x1 += crtc->x;
    333         b.y1 += crtc->y;
    334         b.x2 += crtc->x;
    335         b.y2 += crtc->y;
    336     }
    337 
    338     return (0 <= b.x1 && b.x2 <= pScrn->virtualX &&
    339             0 <= b.y1 && b.y2 <= pScrn->virtualY);
    340 }
    341 
    342 Bool
    343 xf86CrtcRotate(xf86CrtcPtr crtc)
    344 {
    345     ScrnInfoPtr pScrn = crtc->scrn;
    346     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    347     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
    348     PictTransform crtc_to_fb;
    349     struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
    350     xFixed *new_params = NULL;
    351     int new_nparams = 0;
    352     PictFilterPtr new_filter = NULL;
    353     int new_width = 0;
    354     int new_height = 0;
    355     RRTransformPtr transform = NULL;
    356     Bool damage = FALSE;
    357 
    358     if (pScreen->isGPU)
    359         return TRUE;
    360     if (crtc->transformPresent)
    361         transform = &crtc->transform;
    362 
    363     if (!RRTransformCompute(crtc->x, crtc->y,
    364                             crtc->mode.HDisplay, crtc->mode.VDisplay,
    365                             crtc->rotation,
    366                             transform,
    367                             &crtc_to_fb,
    368                             &f_crtc_to_fb,
    369                             &f_fb_to_crtc) &&
    370         xf86CrtcFitsScreen(crtc, &f_crtc_to_fb)) {
    371         /*
    372          * If the untranslated transformation is the identity,
    373          * disable the shadow buffer
    374          */
    375         xf86RotateDestroy(crtc);
    376         crtc->transform_in_use = FALSE;
    377         free(new_params);
    378         new_params = NULL;
    379         new_nparams = 0;
    380         new_filter = NULL;
    381         new_width = 0;
    382         new_height = 0;
    383     }
    384     else {
    385         if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput) {
    386             xf86RotateDestroy(crtc);
    387         }
    388         else {
    389             /*
    390              * these are the size of the shadow pixmap, which
    391              * matches the mode, not the pre-rotated copy in the
    392              * frame buffer
    393              */
    394             int width = crtc->mode.HDisplay;
    395             int height = crtc->mode.VDisplay;
    396             void *shadowData = crtc->rotatedData;
    397             PixmapPtr shadow = crtc->rotatedPixmap;
    398             int old_width = shadow ? shadow->drawable.width : 0;
    399             int old_height = shadow ? shadow->drawable.height : 0;
    400 
    401             /* Allocate memory for rotation */
    402             if (old_width != width || old_height != height) {
    403                 if (shadow || shadowData) {
    404                     crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
    405                     crtc->rotatedPixmap = NULL;
    406                     crtc->rotatedData = NULL;
    407                 }
    408                 shadowData = crtc->funcs->shadow_allocate(crtc, width, height);
    409                 if (!shadowData)
    410                     goto bail1;
    411                 crtc->rotatedData = shadowData;
    412                 /* shadow will be damaged in xf86RotatePrepare */
    413             }
    414             else {
    415                 /* mark shadowed area as damaged so it will be repainted */
    416                 damage = TRUE;
    417             }
    418 
    419             if (!xf86_config->rotation_damage) {
    420                 /* Create damage structure */
    421                 xf86_config->rotation_damage = DamageCreate(NULL, NULL,
    422                                                             DamageReportNone,
    423                                                             TRUE, pScreen,
    424                                                             pScreen);
    425                 if (!xf86_config->rotation_damage)
    426                     goto bail2;
    427 
    428                 /* Wrap block handler */
    429                 if (!xf86_config->BlockHandler) {
    430                     xf86_config->BlockHandler = pScreen->BlockHandler;
    431                     pScreen->BlockHandler = xf86RotateBlockHandler;
    432                 }
    433             }
    434 
    435             if (0) {
    436  bail2:
    437                 if (shadow || shadowData) {
    438                     crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
    439                     crtc->rotatedPixmap = NULL;
    440                     crtc->rotatedData = NULL;
    441                 }
    442  bail1:
    443                 if (old_width && old_height)
    444                     crtc->rotatedPixmap =
    445                         crtc->funcs->shadow_create(crtc, NULL, old_width,
    446                                                    old_height);
    447                 return FALSE;
    448             }
    449         }
    450 #ifdef RANDR_12_INTERFACE
    451         if (transform) {
    452             if (transform->nparams) {
    453                 new_params = malloc(transform->nparams * sizeof(xFixed));
    454                 if (new_params) {
    455                     memcpy(new_params, transform->params,
    456                            transform->nparams * sizeof(xFixed));
    457                     new_nparams = transform->nparams;
    458                     new_filter = transform->filter;
    459                 }
    460             }
    461             else
    462                 new_filter = transform->filter;
    463             if (new_filter) {
    464                 new_width = new_filter->width;
    465                 new_height = new_filter->height;
    466             }
    467         }
    468 #endif
    469         crtc->transform_in_use = TRUE;
    470     }
    471     crtc->crtc_to_framebuffer = crtc_to_fb;
    472     crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
    473     crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
    474     free(crtc->params);
    475     crtc->params = new_params;
    476     crtc->nparams = new_nparams;
    477     crtc->filter = new_filter;
    478     crtc->filter_width = new_width;
    479     crtc->filter_height = new_height;
    480     crtc->bounds.x1 = 0;
    481     crtc->bounds.x2 = crtc->mode.HDisplay;
    482     crtc->bounds.y1 = 0;
    483     crtc->bounds.y2 = crtc->mode.VDisplay;
    484     pixman_f_transform_bounds(&f_crtc_to_fb, &crtc->bounds);
    485 
    486     if (damage)
    487         xf86CrtcDamageShadow(crtc);
    488     else if (crtc->rotatedData && !crtc->rotatedPixmap)
    489         /* Make sure the new rotate buffer has valid transformed contents */
    490         xf86RotateRedisplay(pScreen);
    491 
    492     /* All done */
    493     return TRUE;
    494 }