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