pixmap.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1993, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included
1205b261ecSmrgin all copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg
2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall
2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or
2405b261ecSmrgother dealings in this Software without prior written authorization
2505b261ecSmrgfrom The Open Group.
2605b261ecSmrg
2705b261ecSmrg*/
2805b261ecSmrg
2905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3005b261ecSmrg#include <dix-config.h>
3105b261ecSmrg#endif
3205b261ecSmrg
3305b261ecSmrg#include <X11/X.h>
3405b261ecSmrg#include "scrnintstr.h"
3505b261ecSmrg#include "misc.h"
3605b261ecSmrg#include "os.h"
3705b261ecSmrg#include "windowstr.h"
3805b261ecSmrg#include "resource.h"
3905b261ecSmrg#include "dixstruct.h"
4005b261ecSmrg#include "gcstruct.h"
4105b261ecSmrg#include "servermd.h"
4205b261ecSmrg#include "site.h"
4335c4bbdfSmrg#include "X11/extensions/render.h"
4435c4bbdfSmrg#include "picturestr.h"
4535c4bbdfSmrg#include "randrstr.h"
4605b261ecSmrg/*
4705b261ecSmrg *  Scratch pixmap management and device independent pixmap allocation
4805b261ecSmrg *  function.
4905b261ecSmrg */
5005b261ecSmrg
5105b261ecSmrg/* callable by ddx */
526747b715SmrgPixmapPtr
5335c4bbdfSmrgGetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth,
5435c4bbdfSmrg                       int bitsPerPixel, int devKind, void *pPixData)
5505b261ecSmrg{
5605b261ecSmrg    PixmapPtr pPixmap = pScreen->pScratchPixmap;
5705b261ecSmrg
5805b261ecSmrg    if (pPixmap)
5935c4bbdfSmrg        pScreen->pScratchPixmap = NULL;
6005b261ecSmrg    else
6135c4bbdfSmrg        /* width and height of 0 means don't allocate any pixmap data */
6235c4bbdfSmrg        pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
6305b261ecSmrg
6405b261ecSmrg    if (pPixmap) {
6535c4bbdfSmrg        if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
6635c4bbdfSmrg                                            bitsPerPixel, devKind, pPixData))
6735c4bbdfSmrg            return pPixmap;
6835c4bbdfSmrg        (*pScreen->DestroyPixmap) (pPixmap);
6905b261ecSmrg    }
7005b261ecSmrg    return NullPixmap;
7105b261ecSmrg}
7205b261ecSmrg
7305b261ecSmrg/* callable by ddx */
746747b715Smrgvoid
7505b261ecSmrgFreeScratchPixmapHeader(PixmapPtr pPixmap)
7605b261ecSmrg{
7735c4bbdfSmrg    if (pPixmap) {
7835c4bbdfSmrg        ScreenPtr pScreen = pPixmap->drawable.pScreen;
7935c4bbdfSmrg
8035c4bbdfSmrg        pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */
8135c4bbdfSmrg        if (pScreen->pScratchPixmap)
8235c4bbdfSmrg            (*pScreen->DestroyPixmap) (pPixmap);
8335c4bbdfSmrg        else
8435c4bbdfSmrg            pScreen->pScratchPixmap = pPixmap;
8505b261ecSmrg    }
8605b261ecSmrg}
8705b261ecSmrg
8805b261ecSmrgBool
8935c4bbdfSmrgCreateScratchPixmapsForScreen(ScreenPtr pScreen)
9005b261ecSmrg{
9135c4bbdfSmrg    unsigned int pixmap_size;
926747b715Smrg
9335c4bbdfSmrg    pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP);
9435c4bbdfSmrg    pScreen->totalPixmapSize =
9535c4bbdfSmrg        BitmapBytePad(pixmap_size * 8);
966747b715Smrg
9705b261ecSmrg    /* let it be created on first use */
9835c4bbdfSmrg    pScreen->pScratchPixmap = NULL;
9905b261ecSmrg    return TRUE;
10005b261ecSmrg}
10105b261ecSmrg
10205b261ecSmrgvoid
10335c4bbdfSmrgFreeScratchPixmapsForScreen(ScreenPtr pScreen)
10405b261ecSmrg{
10535c4bbdfSmrg    FreeScratchPixmapHeader(pScreen->pScratchPixmap);
10605b261ecSmrg}
10705b261ecSmrg
10805b261ecSmrg/* callable by ddx */
1096747b715SmrgPixmapPtr
11005b261ecSmrgAllocatePixmap(ScreenPtr pScreen, int pixDataSize)
11105b261ecSmrg{
11205b261ecSmrg    PixmapPtr pPixmap;
11305b261ecSmrg
1146747b715Smrg    assert(pScreen->totalPixmapSize > 0);
1156747b715Smrg
11635c4bbdfSmrg    if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize)
11735c4bbdfSmrg        return NullPixmap;
11835c4bbdfSmrg
1196747b715Smrg    pPixmap = malloc(pScreen->totalPixmapSize + pixDataSize);
12005b261ecSmrg    if (!pPixmap)
12135c4bbdfSmrg        return NullPixmap;
12205b261ecSmrg
12335c4bbdfSmrg    dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP);
12405b261ecSmrg    return pPixmap;
12505b261ecSmrg}
1266747b715Smrg
1276747b715Smrg/* callable by ddx */
1286747b715Smrgvoid
1296747b715SmrgFreePixmap(PixmapPtr pPixmap)
1306747b715Smrg{
1316747b715Smrg    dixFiniPrivates(pPixmap, PRIVATE_PIXMAP);
1326747b715Smrg    free(pPixmap);
1336747b715Smrg}
13435c4bbdfSmrg
13535c4bbdfSmrgPixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave)
13635c4bbdfSmrg{
13735c4bbdfSmrg    PixmapPtr spix;
13835c4bbdfSmrg    int ret;
13935c4bbdfSmrg    void *handle;
14035c4bbdfSmrg    ScreenPtr master = pixmap->drawable.pScreen;
14135c4bbdfSmrg    int depth = pixmap->drawable.depth;
14235c4bbdfSmrg
14335c4bbdfSmrg    ret = master->SharePixmapBacking(pixmap, slave, &handle);
14435c4bbdfSmrg    if (ret == FALSE)
14535c4bbdfSmrg        return NULL;
14635c4bbdfSmrg
14735c4bbdfSmrg    spix = slave->CreatePixmap(slave, 0, 0, depth,
14835c4bbdfSmrg                               CREATE_PIXMAP_USAGE_SHARED);
14935c4bbdfSmrg    slave->ModifyPixmapHeader(spix, pixmap->drawable.width,
15035c4bbdfSmrg                              pixmap->drawable.height, depth, 0,
15135c4bbdfSmrg                              pixmap->devKind, NULL);
15235c4bbdfSmrg
15335c4bbdfSmrg    /* have the slave pixmap take a reference on the master pixmap
15435c4bbdfSmrg       later we destroy them both at the same time */
15535c4bbdfSmrg    pixmap->refcnt++;
15635c4bbdfSmrg
15735c4bbdfSmrg    spix->master_pixmap = pixmap;
15835c4bbdfSmrg
15935c4bbdfSmrg    ret = slave->SetSharedPixmapBacking(spix, handle);
16035c4bbdfSmrg    if (ret == FALSE) {
16135c4bbdfSmrg        slave->DestroyPixmap(spix);
16235c4bbdfSmrg        return NULL;
16335c4bbdfSmrg    }
16435c4bbdfSmrg
16535c4bbdfSmrg    return spix;
16635c4bbdfSmrg}
16735c4bbdfSmrg
16835c4bbdfSmrgBool
16935c4bbdfSmrgPixmapStartDirtyTracking(PixmapPtr src,
17035c4bbdfSmrg                         PixmapPtr slave_dst,
17135c4bbdfSmrg                         int x, int y, int dst_x, int dst_y,
17235c4bbdfSmrg                         Rotation rotation)
17335c4bbdfSmrg{
17435c4bbdfSmrg    ScreenPtr screen = src->drawable.pScreen;
17535c4bbdfSmrg    PixmapDirtyUpdatePtr dirty_update;
17635c4bbdfSmrg    RegionPtr damageregion;
17735c4bbdfSmrg    RegionRec dstregion;
17835c4bbdfSmrg    BoxRec box;
17935c4bbdfSmrg
18035c4bbdfSmrg    dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec));
18135c4bbdfSmrg    if (!dirty_update)
18235c4bbdfSmrg        return FALSE;
18335c4bbdfSmrg
18435c4bbdfSmrg    dirty_update->src = src;
18535c4bbdfSmrg    dirty_update->slave_dst = slave_dst;
18635c4bbdfSmrg    dirty_update->x = x;
18735c4bbdfSmrg    dirty_update->y = y;
18835c4bbdfSmrg    dirty_update->dst_x = dst_x;
18935c4bbdfSmrg    dirty_update->dst_y = dst_y;
19035c4bbdfSmrg    dirty_update->rotation = rotation;
19135c4bbdfSmrg    dirty_update->damage = DamageCreate(NULL, NULL,
19235c4bbdfSmrg                                        DamageReportNone,
19335c4bbdfSmrg                                        TRUE, src->drawable.pScreen,
19435c4bbdfSmrg                                        src->drawable.pScreen);
19535c4bbdfSmrg
19635c4bbdfSmrg    if (rotation != RR_Rotate_0) {
19735c4bbdfSmrg        RRTransformCompute(x, y,
19835c4bbdfSmrg                           slave_dst->drawable.width,
19935c4bbdfSmrg                           slave_dst->drawable.height,
20035c4bbdfSmrg                           rotation,
20135c4bbdfSmrg                           NULL,
20235c4bbdfSmrg                           &dirty_update->transform,
20335c4bbdfSmrg                           &dirty_update->f_transform,
20435c4bbdfSmrg                           &dirty_update->f_inverse);
20535c4bbdfSmrg    }
20635c4bbdfSmrg    if (!dirty_update->damage) {
20735c4bbdfSmrg        free(dirty_update);
20835c4bbdfSmrg        return FALSE;
20935c4bbdfSmrg    }
21035c4bbdfSmrg
21135c4bbdfSmrg    /* Damage destination rectangle so that the destination pixmap contents
21235c4bbdfSmrg     * will get fully initialized
21335c4bbdfSmrg     */
21435c4bbdfSmrg    box.x1 = dirty_update->x;
21535c4bbdfSmrg    box.y1 = dirty_update->y;
21635c4bbdfSmrg    if (dirty_update->rotation == RR_Rotate_90 ||
21735c4bbdfSmrg        dirty_update->rotation == RR_Rotate_270) {
21835c4bbdfSmrg        box.x2 = dirty_update->x + slave_dst->drawable.height;
21935c4bbdfSmrg        box.y2 = dirty_update->y + slave_dst->drawable.width;
22035c4bbdfSmrg    } else {
22135c4bbdfSmrg        box.x2 = dirty_update->x + slave_dst->drawable.width;
22235c4bbdfSmrg        box.y2 = dirty_update->y + slave_dst->drawable.height;
22335c4bbdfSmrg    }
22435c4bbdfSmrg    RegionInit(&dstregion, &box, 1);
22535c4bbdfSmrg    damageregion = DamageRegion(dirty_update->damage);
22635c4bbdfSmrg    RegionUnion(damageregion, damageregion, &dstregion);
22735c4bbdfSmrg    RegionUninit(&dstregion);
22835c4bbdfSmrg
22935c4bbdfSmrg    DamageRegister(&src->drawable, dirty_update->damage);
23035c4bbdfSmrg    xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list);
23135c4bbdfSmrg    return TRUE;
23235c4bbdfSmrg}
23335c4bbdfSmrg
23435c4bbdfSmrgBool
23535c4bbdfSmrgPixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst)
23635c4bbdfSmrg{
23735c4bbdfSmrg    ScreenPtr screen = src->drawable.pScreen;
23835c4bbdfSmrg    PixmapDirtyUpdatePtr ent, safe;
23935c4bbdfSmrg
24035c4bbdfSmrg    xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) {
24135c4bbdfSmrg        if (ent->src == src && ent->slave_dst == slave_dst) {
24235c4bbdfSmrg            DamageDestroy(ent->damage);
24335c4bbdfSmrg            xorg_list_del(&ent->ent);
24435c4bbdfSmrg            free(ent);
24535c4bbdfSmrg        }
24635c4bbdfSmrg    }
24735c4bbdfSmrg    return TRUE;
24835c4bbdfSmrg}
24935c4bbdfSmrg
25035c4bbdfSmrgstatic void
25135c4bbdfSmrgPixmapDirtyCopyArea(PixmapPtr dst,
25235c4bbdfSmrg                    PixmapDirtyUpdatePtr dirty,
25335c4bbdfSmrg                    RegionPtr dirty_region)
25435c4bbdfSmrg{
25535c4bbdfSmrg    ScreenPtr pScreen = dirty->src->drawable.pScreen;
25635c4bbdfSmrg    int n;
25735c4bbdfSmrg    BoxPtr b;
25835c4bbdfSmrg    GCPtr pGC;
25935c4bbdfSmrg
26035c4bbdfSmrg    n = RegionNumRects(dirty_region);
26135c4bbdfSmrg    b = RegionRects(dirty_region);
26235c4bbdfSmrg
26335c4bbdfSmrg    pGC = GetScratchGC(dirty->src->drawable.depth, pScreen);
26435c4bbdfSmrg    ValidateGC(&dst->drawable, pGC);
26535c4bbdfSmrg
26635c4bbdfSmrg    while (n--) {
26735c4bbdfSmrg        BoxRec dst_box;
26835c4bbdfSmrg        int w, h;
26935c4bbdfSmrg
27035c4bbdfSmrg        dst_box = *b;
27135c4bbdfSmrg        w = dst_box.x2 - dst_box.x1;
27235c4bbdfSmrg        h = dst_box.y2 - dst_box.y1;
27335c4bbdfSmrg
27435c4bbdfSmrg        pGC->ops->CopyArea(&dirty->src->drawable, &dst->drawable, pGC,
27535c4bbdfSmrg                           dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h,
27635c4bbdfSmrg                           dirty->dst_x + dst_box.x1,
27735c4bbdfSmrg                           dirty->dst_y + dst_box.y1);
27835c4bbdfSmrg        b++;
27935c4bbdfSmrg    }
28035c4bbdfSmrg    FreeScratchGC(pGC);
28135c4bbdfSmrg}
28235c4bbdfSmrg
28335c4bbdfSmrgstatic void
28435c4bbdfSmrgPixmapDirtyCompositeRotate(PixmapPtr dst_pixmap,
28535c4bbdfSmrg                           PixmapDirtyUpdatePtr dirty,
28635c4bbdfSmrg                           RegionPtr dirty_region)
28735c4bbdfSmrg{
28835c4bbdfSmrg    ScreenPtr pScreen = dirty->src->drawable.pScreen;
28935c4bbdfSmrg    PictFormatPtr format = PictureWindowFormat(pScreen->root);
29035c4bbdfSmrg    PicturePtr src, dst;
29135c4bbdfSmrg    XID include_inferiors = IncludeInferiors;
29235c4bbdfSmrg    int n = RegionNumRects(dirty_region);
29335c4bbdfSmrg    BoxPtr b = RegionRects(dirty_region);
29435c4bbdfSmrg    int error;
29535c4bbdfSmrg
29635c4bbdfSmrg    src = CreatePicture(None,
29735c4bbdfSmrg                        &dirty->src->drawable,
29835c4bbdfSmrg                        format,
29935c4bbdfSmrg                        CPSubwindowMode,
30035c4bbdfSmrg                        &include_inferiors, serverClient, &error);
30135c4bbdfSmrg    if (!src)
30235c4bbdfSmrg        return;
30335c4bbdfSmrg
30435c4bbdfSmrg    dst = CreatePicture(None,
30535c4bbdfSmrg                        &dst_pixmap->drawable,
30635c4bbdfSmrg                        format, 0L, NULL, serverClient, &error);
30735c4bbdfSmrg    if (!dst)
30835c4bbdfSmrg        return;
30935c4bbdfSmrg
31035c4bbdfSmrg    error = SetPictureTransform(src, &dirty->transform);
31135c4bbdfSmrg    if (error)
31235c4bbdfSmrg        return;
31335c4bbdfSmrg    while (n--) {
31435c4bbdfSmrg        BoxRec dst_box;
31535c4bbdfSmrg
31635c4bbdfSmrg        dst_box = *b;
31735c4bbdfSmrg        dst_box.x1 += dirty->x;
31835c4bbdfSmrg        dst_box.x2 += dirty->x;
31935c4bbdfSmrg        dst_box.y1 += dirty->y;
32035c4bbdfSmrg        dst_box.y2 += dirty->y;
32135c4bbdfSmrg        pixman_f_transform_bounds(&dirty->f_inverse, &dst_box);
32235c4bbdfSmrg
32335c4bbdfSmrg        CompositePicture(PictOpSrc,
32435c4bbdfSmrg                         src, NULL, dst,
32535c4bbdfSmrg                         dst_box.x1,
32635c4bbdfSmrg                         dst_box.y1,
32735c4bbdfSmrg                         0, 0,
32835c4bbdfSmrg                         dst_box.x1,
32935c4bbdfSmrg                         dst_box.y1,
33035c4bbdfSmrg                         dst_box.x2 - dst_box.x1,
33135c4bbdfSmrg                         dst_box.y2 - dst_box.y1);
33235c4bbdfSmrg        b++;
33335c4bbdfSmrg    }
33435c4bbdfSmrg
33535c4bbdfSmrg    FreePicture(src, None);
33635c4bbdfSmrg    FreePicture(dst, None);
33735c4bbdfSmrg}
33835c4bbdfSmrg
33935c4bbdfSmrg/*
34035c4bbdfSmrg * this function can possibly be improved and optimised, by clipping
34135c4bbdfSmrg * instead of iterating
34235c4bbdfSmrg * Drivers are free to implement their own version of this.
34335c4bbdfSmrg */
34435c4bbdfSmrgBool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
34535c4bbdfSmrg{
34635c4bbdfSmrg    ScreenPtr pScreen = dirty->src->drawable.pScreen;
34735c4bbdfSmrg    RegionPtr region = DamageRegion(dirty->damage);
34835c4bbdfSmrg    PixmapPtr dst;
34935c4bbdfSmrg    SourceValidateProcPtr SourceValidate;
35035c4bbdfSmrg    RegionRec pixregion;
35135c4bbdfSmrg    BoxRec box;
35235c4bbdfSmrg
35335c4bbdfSmrg    dst = dirty->slave_dst->master_pixmap;
35435c4bbdfSmrg    if (!dst)
35535c4bbdfSmrg        dst = dirty->slave_dst;
35635c4bbdfSmrg
35735c4bbdfSmrg    box.x1 = 0;
35835c4bbdfSmrg    box.y1 = 0;
35935c4bbdfSmrg    if (dirty->rotation == RR_Rotate_90 ||
36035c4bbdfSmrg        dirty->rotation == RR_Rotate_270) {
36135c4bbdfSmrg        box.x2 = dst->drawable.height;
36235c4bbdfSmrg        box.y2 = dst->drawable.width;
36335c4bbdfSmrg    } else {
36435c4bbdfSmrg        box.x2 = dst->drawable.width;
36535c4bbdfSmrg        box.y2 = dst->drawable.height;
36635c4bbdfSmrg    }
36735c4bbdfSmrg    RegionInit(&pixregion, &box, 1);
36835c4bbdfSmrg
36935c4bbdfSmrg    /*
37035c4bbdfSmrg     * SourceValidate is used by the software cursor code
37135c4bbdfSmrg     * to pull the cursor off of the screen when reading
37235c4bbdfSmrg     * bits from the frame buffer. Bypassing this function
37335c4bbdfSmrg     * leaves the software cursor in place
37435c4bbdfSmrg     */
37535c4bbdfSmrg    SourceValidate = pScreen->SourceValidate;
37635c4bbdfSmrg    pScreen->SourceValidate = NULL;
37735c4bbdfSmrg
37835c4bbdfSmrg    RegionTranslate(&pixregion, dirty->x, dirty->y);
37935c4bbdfSmrg    RegionIntersect(&pixregion, &pixregion, region);
38035c4bbdfSmrg
38135c4bbdfSmrg    if (RegionNil(&pixregion)) {
38235c4bbdfSmrg        RegionUninit(&pixregion);
38335c4bbdfSmrg        return FALSE;
38435c4bbdfSmrg    }
38535c4bbdfSmrg
38635c4bbdfSmrg    RegionTranslate(&pixregion, -dirty->x, -dirty->y);
38735c4bbdfSmrg
38835c4bbdfSmrg    if (!pScreen->root || dirty->rotation == RR_Rotate_0)
38935c4bbdfSmrg        PixmapDirtyCopyArea(dst, dirty, &pixregion);
39035c4bbdfSmrg    else
39135c4bbdfSmrg        PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
39235c4bbdfSmrg    pScreen->SourceValidate = SourceValidate;
39335c4bbdfSmrg    return TRUE;
39435c4bbdfSmrg}
395