xserver

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

pixmap.c (12181B)


      1 /*
      2 
      3 Copyright 1993, 1998  The Open Group
      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
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 */
     28 
     29 #ifdef HAVE_DIX_CONFIG_H
     30 #include <dix-config.h>
     31 #endif
     32 
     33 #include <X11/X.h>
     34 #include "scrnintstr.h"
     35 #include "mi.h"
     36 #include "misc.h"
     37 #include "os.h"
     38 #include "windowstr.h"
     39 #include "resource.h"
     40 #include "dixstruct.h"
     41 #include "gcstruct.h"
     42 #include "servermd.h"
     43 #include "X11/extensions/render.h"
     44 #include "picturestr.h"
     45 #include "randrstr.h"
     46 /*
     47  *  Scratch pixmap management and device independent pixmap allocation
     48  *  function.
     49  */
     50 
     51 /* callable by ddx */
     52 PixmapPtr
     53 GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth,
     54                        int bitsPerPixel, int devKind, void *pPixData)
     55 {
     56     PixmapPtr pPixmap = pScreen->pScratchPixmap;
     57 
     58     if (pPixmap)
     59         pScreen->pScratchPixmap = NULL;
     60     else
     61         /* width and height of 0 means don't allocate any pixmap data */
     62         pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
     63 
     64     if (pPixmap) {
     65         if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
     66                                             bitsPerPixel, devKind, pPixData))
     67             return pPixmap;
     68         (*pScreen->DestroyPixmap) (pPixmap);
     69     }
     70     return NullPixmap;
     71 }
     72 
     73 /* callable by ddx */
     74 void
     75 FreeScratchPixmapHeader(PixmapPtr pPixmap)
     76 {
     77     if (pPixmap) {
     78         ScreenPtr pScreen = pPixmap->drawable.pScreen;
     79 
     80         pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */
     81         if (pScreen->pScratchPixmap)
     82             (*pScreen->DestroyPixmap) (pPixmap);
     83         else
     84             pScreen->pScratchPixmap = pPixmap;
     85     }
     86 }
     87 
     88 Bool
     89 CreateScratchPixmapsForScreen(ScreenPtr pScreen)
     90 {
     91     unsigned int pixmap_size;
     92 
     93     pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP);
     94     pScreen->totalPixmapSize =
     95         BitmapBytePad(pixmap_size * 8);
     96 
     97     /* let it be created on first use */
     98     pScreen->pScratchPixmap = NULL;
     99     return TRUE;
    100 }
    101 
    102 void
    103 FreeScratchPixmapsForScreen(ScreenPtr pScreen)
    104 {
    105     FreeScratchPixmapHeader(pScreen->pScratchPixmap);
    106 }
    107 
    108 /* callable by ddx */
    109 PixmapPtr
    110 AllocatePixmap(ScreenPtr pScreen, int pixDataSize)
    111 {
    112     PixmapPtr pPixmap;
    113 
    114     assert(pScreen->totalPixmapSize > 0);
    115 
    116     if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize)
    117         return NullPixmap;
    118 
    119     pPixmap = calloc(1, pScreen->totalPixmapSize + pixDataSize);
    120     if (!pPixmap)
    121         return NullPixmap;
    122 
    123     dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP);
    124     return pPixmap;
    125 }
    126 
    127 /* callable by ddx */
    128 void
    129 FreePixmap(PixmapPtr pPixmap)
    130 {
    131     dixFiniPrivates(pPixmap, PRIVATE_PIXMAP);
    132     free(pPixmap);
    133 }
    134 
    135 void PixmapUnshareSecondaryPixmap(PixmapPtr secondary_pixmap)
    136 {
    137      int ihandle = -1;
    138      ScreenPtr pScreen = secondary_pixmap->drawable.pScreen;
    139      pScreen->SetSharedPixmapBacking(secondary_pixmap, ((void *)(long)ihandle));
    140 }
    141 
    142 PixmapPtr PixmapShareToSecondary(PixmapPtr pixmap, ScreenPtr secondary)
    143 {
    144     PixmapPtr spix;
    145     int ret;
    146     void *handle;
    147     ScreenPtr primary = pixmap->drawable.pScreen;
    148     int depth = pixmap->drawable.depth;
    149 
    150     ret = primary->SharePixmapBacking(pixmap, secondary, &handle);
    151     if (ret == FALSE)
    152         return NULL;
    153 
    154     spix = secondary->CreatePixmap(secondary, 0, 0, depth,
    155                                CREATE_PIXMAP_USAGE_SHARED);
    156     secondary->ModifyPixmapHeader(spix, pixmap->drawable.width,
    157                                   pixmap->drawable.height, depth, 0,
    158                                   pixmap->devKind, NULL);
    159 
    160     /* have the secondary pixmap take a reference on the primary pixmap
    161        later we destroy them both at the same time */
    162     pixmap->refcnt++;
    163 
    164     spix->primary_pixmap = pixmap;
    165 
    166     ret = secondary->SetSharedPixmapBacking(spix, handle);
    167     if (ret == FALSE) {
    168         secondary->DestroyPixmap(spix);
    169         return NULL;
    170     }
    171 
    172     return spix;
    173 }
    174 
    175 static void
    176 PixmapDirtyDamageDestroy(DamagePtr damage, void *closure)
    177 {
    178     PixmapDirtyUpdatePtr dirty = closure;
    179 
    180     dirty->damage = NULL;
    181 }
    182 
    183 Bool
    184 PixmapStartDirtyTracking(DrawablePtr src,
    185                          PixmapPtr secondary_dst,
    186                          int x, int y, int dst_x, int dst_y,
    187                          Rotation rotation)
    188 {
    189     ScreenPtr screen = src->pScreen;
    190     PixmapDirtyUpdatePtr dirty_update;
    191     RegionPtr damageregion;
    192     RegionRec dstregion;
    193     BoxRec box;
    194 
    195     dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec));
    196     if (!dirty_update)
    197         return FALSE;
    198 
    199     dirty_update->src = src;
    200     dirty_update->secondary_dst = secondary_dst;
    201     dirty_update->x = x;
    202     dirty_update->y = y;
    203     dirty_update->dst_x = dst_x;
    204     dirty_update->dst_y = dst_y;
    205     dirty_update->rotation = rotation;
    206     dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy,
    207                                         DamageReportNone, TRUE, screen,
    208                                         dirty_update);
    209 
    210     if (rotation != RR_Rotate_0) {
    211         RRTransformCompute(x, y,
    212                            secondary_dst->drawable.width,
    213                            secondary_dst->drawable.height,
    214                            rotation,
    215                            NULL,
    216                            &dirty_update->transform,
    217                            &dirty_update->f_transform,
    218                            &dirty_update->f_inverse);
    219     }
    220     if (!dirty_update->damage) {
    221         free(dirty_update);
    222         return FALSE;
    223     }
    224 
    225     /* Damage destination rectangle so that the destination pixmap contents
    226      * will get fully initialized
    227      */
    228     box.x1 = dirty_update->x;
    229     box.y1 = dirty_update->y;
    230     if (dirty_update->rotation == RR_Rotate_90 ||
    231         dirty_update->rotation == RR_Rotate_270) {
    232         box.x2 = dirty_update->x + secondary_dst->drawable.height;
    233         box.y2 = dirty_update->y + secondary_dst->drawable.width;
    234     } else {
    235         box.x2 = dirty_update->x + secondary_dst->drawable.width;
    236         box.y2 = dirty_update->y + secondary_dst->drawable.height;
    237     }
    238     RegionInit(&dstregion, &box, 1);
    239     damageregion = DamageRegion(dirty_update->damage);
    240     RegionUnion(damageregion, damageregion, &dstregion);
    241     RegionUninit(&dstregion);
    242 
    243     DamageRegister(src, dirty_update->damage);
    244     xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list);
    245     return TRUE;
    246 }
    247 
    248 Bool
    249 PixmapStopDirtyTracking(DrawablePtr src, PixmapPtr secondary_dst)
    250 {
    251     ScreenPtr screen = src->pScreen;
    252     PixmapDirtyUpdatePtr ent, safe;
    253 
    254     xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) {
    255         if (ent->src == src && ent->secondary_dst == secondary_dst) {
    256             if (ent->damage)
    257                 DamageDestroy(ent->damage);
    258             xorg_list_del(&ent->ent);
    259             free(ent);
    260         }
    261     }
    262     return TRUE;
    263 }
    264 
    265 static void
    266 PixmapDirtyCopyArea(PixmapPtr dst,
    267                     PixmapDirtyUpdatePtr dirty,
    268                     RegionPtr dirty_region)
    269 {
    270     DrawablePtr src = dirty->src;
    271     ScreenPtr pScreen = src->pScreen;
    272     int n;
    273     BoxPtr b;
    274     GCPtr pGC;
    275 
    276     n = RegionNumRects(dirty_region);
    277     b = RegionRects(dirty_region);
    278 
    279     pGC = GetScratchGC(src->depth, pScreen);
    280     if (pScreen->root) {
    281         ChangeGCVal subWindowMode;
    282 
    283         subWindowMode.val = IncludeInferiors;
    284         ChangeGC(NullClient, pGC, GCSubwindowMode, &subWindowMode);
    285     }
    286     ValidateGC(&dst->drawable, pGC);
    287 
    288     while (n--) {
    289         BoxRec dst_box;
    290         int w, h;
    291 
    292         dst_box = *b;
    293         w = dst_box.x2 - dst_box.x1;
    294         h = dst_box.y2 - dst_box.y1;
    295 
    296         pGC->ops->CopyArea(src, &dst->drawable, pGC,
    297                            dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h,
    298                            dirty->dst_x + dst_box.x1,
    299                            dirty->dst_y + dst_box.y1);
    300         b++;
    301     }
    302     FreeScratchGC(pGC);
    303 }
    304 
    305 static void
    306 PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap,
    307                            PixmapDirtyUpdatePtr dirty,
    308                            RegionPtr dirty_region)
    309 {
    310     ScreenPtr pScreen = dirty->src->pScreen;
    311     PictFormatPtr format = PictureWindowFormat(pScreen->root);
    312     PicturePtr src, dst;
    313     XID include_inferiors = IncludeInferiors;
    314     int n = RegionNumRects(dirty_region);
    315     BoxPtr b = RegionRects(dirty_region);
    316     int error;
    317 
    318     src = CreatePicture(None,
    319                         dirty->src,
    320                         format,
    321                         CPSubwindowMode,
    322                         &include_inferiors, serverClient, &error);
    323     if (!src)
    324         return;
    325 
    326     dst = CreatePicture(None,
    327                         &dst_pixmap->drawable,
    328                         format, 0L, NULL, serverClient, &error);
    329     if (!dst)
    330         return;
    331 
    332     error = SetPictureTransform(src, &dirty->transform);
    333     if (error)
    334         return;
    335     while (n--) {
    336         BoxRec dst_box;
    337 
    338         dst_box = *b;
    339         dst_box.x1 += dirty->x;
    340         dst_box.x2 += dirty->x;
    341         dst_box.y1 += dirty->y;
    342         dst_box.y2 += dirty->y;
    343         pixman_f_transform_bounds(&dirty->f_inverse, &dst_box);
    344 
    345         CompositePicture(PictOpSrc,
    346                          src, NULL, dst,
    347                          dst_box.x1,
    348                          dst_box.y1,
    349                          0, 0,
    350                          dst_box.x1,
    351                          dst_box.y1,
    352                          dst_box.x2 - dst_box.x1,
    353                          dst_box.y2 - dst_box.y1);
    354         b++;
    355     }
    356 
    357     FreePicture(src, None);
    358     FreePicture(dst, None);
    359 }
    360 
    361 /*
    362  * this function can possibly be improved and optimised, by clipping
    363  * instead of iterating
    364  * Drivers are free to implement their own version of this.
    365  */
    366 Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
    367 {
    368     ScreenPtr pScreen = dirty->src->pScreen;
    369     RegionPtr region = DamageRegion(dirty->damage);
    370     PixmapPtr dst;
    371     SourceValidateProcPtr SourceValidate;
    372     RegionRec pixregion;
    373     BoxRec box;
    374 
    375     dst = dirty->secondary_dst->primary_pixmap;
    376     if (!dst)
    377         dst = dirty->secondary_dst;
    378 
    379     box.x1 = 0;
    380     box.y1 = 0;
    381     if (dirty->rotation == RR_Rotate_90 ||
    382         dirty->rotation == RR_Rotate_270) {
    383         box.x2 = dst->drawable.height;
    384         box.y2 = dst->drawable.width;
    385     } else {
    386         box.x2 = dst->drawable.width;
    387         box.y2 = dst->drawable.height;
    388     }
    389     RegionInit(&pixregion, &box, 1);
    390 
    391     /*
    392      * SourceValidate is used by the software cursor code
    393      * to pull the cursor off of the screen when reading
    394      * bits from the frame buffer. Bypassing this function
    395      * leaves the software cursor in place
    396      */
    397     SourceValidate = pScreen->SourceValidate;
    398     pScreen->SourceValidate = miSourceValidate;
    399 
    400     RegionTranslate(&pixregion, dirty->x, dirty->y);
    401     RegionIntersect(&pixregion, &pixregion, region);
    402 
    403     if (RegionNil(&pixregion)) {
    404         RegionUninit(&pixregion);
    405         return FALSE;
    406     }
    407 
    408     RegionTranslate(&pixregion, -dirty->x, -dirty->y);
    409 
    410     if (!pScreen->root || dirty->rotation == RR_Rotate_0)
    411         PixmapDirtyCopyArea(dst, dirty, &pixregion);
    412     else
    413         PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
    414     pScreen->SourceValidate = SourceValidate;
    415     return TRUE;
    416 }