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" 3525da500fSmrg#include "mi.h" 3605b261ecSmrg#include "misc.h" 3705b261ecSmrg#include "os.h" 3805b261ecSmrg#include "windowstr.h" 3905b261ecSmrg#include "resource.h" 4005b261ecSmrg#include "dixstruct.h" 4105b261ecSmrg#include "gcstruct.h" 4205b261ecSmrg#include "servermd.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 11932414907Smaya pPixmap = calloc(1, 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 1355a112b11Smrgvoid PixmapUnshareSecondaryPixmap(PixmapPtr secondary_pixmap) 1361b5d61b8Smrg{ 1371b5d61b8Smrg int ihandle = -1; 1385a112b11Smrg ScreenPtr pScreen = secondary_pixmap->drawable.pScreen; 1395a112b11Smrg pScreen->SetSharedPixmapBacking(secondary_pixmap, ((void *)(long)ihandle)); 1401b5d61b8Smrg} 1411b5d61b8Smrg 1425a112b11SmrgPixmapPtr PixmapShareToSecondary(PixmapPtr pixmap, ScreenPtr secondary) 14335c4bbdfSmrg{ 14435c4bbdfSmrg PixmapPtr spix; 14535c4bbdfSmrg int ret; 14635c4bbdfSmrg void *handle; 1475a112b11Smrg ScreenPtr primary = pixmap->drawable.pScreen; 14835c4bbdfSmrg int depth = pixmap->drawable.depth; 14935c4bbdfSmrg 1505a112b11Smrg ret = primary->SharePixmapBacking(pixmap, secondary, &handle); 15135c4bbdfSmrg if (ret == FALSE) 15235c4bbdfSmrg return NULL; 15335c4bbdfSmrg 1545a112b11Smrg spix = secondary->CreatePixmap(secondary, 0, 0, depth, 15535c4bbdfSmrg CREATE_PIXMAP_USAGE_SHARED); 1565a112b11Smrg secondary->ModifyPixmapHeader(spix, pixmap->drawable.width, 1575a112b11Smrg pixmap->drawable.height, depth, 0, 1585a112b11Smrg pixmap->devKind, NULL); 15935c4bbdfSmrg 1605a112b11Smrg /* have the secondary pixmap take a reference on the primary pixmap 16135c4bbdfSmrg later we destroy them both at the same time */ 16235c4bbdfSmrg pixmap->refcnt++; 16335c4bbdfSmrg 1645a112b11Smrg spix->primary_pixmap = pixmap; 16535c4bbdfSmrg 1665a112b11Smrg ret = secondary->SetSharedPixmapBacking(spix, handle); 16735c4bbdfSmrg if (ret == FALSE) { 1685a112b11Smrg secondary->DestroyPixmap(spix); 16935c4bbdfSmrg return NULL; 17035c4bbdfSmrg } 17135c4bbdfSmrg 17235c4bbdfSmrg return spix; 17335c4bbdfSmrg} 17435c4bbdfSmrg 1751b5d61b8Smrgstatic void 1761b5d61b8SmrgPixmapDirtyDamageDestroy(DamagePtr damage, void *closure) 1771b5d61b8Smrg{ 1781b5d61b8Smrg PixmapDirtyUpdatePtr dirty = closure; 1791b5d61b8Smrg 1801b5d61b8Smrg dirty->damage = NULL; 1811b5d61b8Smrg} 1821b5d61b8Smrg 18335c4bbdfSmrgBool 1841b5d61b8SmrgPixmapStartDirtyTracking(DrawablePtr src, 1855a112b11Smrg PixmapPtr secondary_dst, 18635c4bbdfSmrg int x, int y, int dst_x, int dst_y, 18735c4bbdfSmrg Rotation rotation) 18835c4bbdfSmrg{ 1891b5d61b8Smrg ScreenPtr screen = src->pScreen; 19035c4bbdfSmrg PixmapDirtyUpdatePtr dirty_update; 19135c4bbdfSmrg RegionPtr damageregion; 19235c4bbdfSmrg RegionRec dstregion; 19335c4bbdfSmrg BoxRec box; 19435c4bbdfSmrg 19535c4bbdfSmrg dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec)); 19635c4bbdfSmrg if (!dirty_update) 19735c4bbdfSmrg return FALSE; 19835c4bbdfSmrg 19935c4bbdfSmrg dirty_update->src = src; 2005a112b11Smrg dirty_update->secondary_dst = secondary_dst; 20135c4bbdfSmrg dirty_update->x = x; 20235c4bbdfSmrg dirty_update->y = y; 20335c4bbdfSmrg dirty_update->dst_x = dst_x; 20435c4bbdfSmrg dirty_update->dst_y = dst_y; 20535c4bbdfSmrg dirty_update->rotation = rotation; 2061b5d61b8Smrg dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy, 2071b5d61b8Smrg DamageReportNone, TRUE, screen, 2081b5d61b8Smrg dirty_update); 20935c4bbdfSmrg 21035c4bbdfSmrg if (rotation != RR_Rotate_0) { 21135c4bbdfSmrg RRTransformCompute(x, y, 2125a112b11Smrg secondary_dst->drawable.width, 2135a112b11Smrg secondary_dst->drawable.height, 21435c4bbdfSmrg rotation, 21535c4bbdfSmrg NULL, 21635c4bbdfSmrg &dirty_update->transform, 21735c4bbdfSmrg &dirty_update->f_transform, 21835c4bbdfSmrg &dirty_update->f_inverse); 21935c4bbdfSmrg } 22035c4bbdfSmrg if (!dirty_update->damage) { 22135c4bbdfSmrg free(dirty_update); 22235c4bbdfSmrg return FALSE; 22335c4bbdfSmrg } 22435c4bbdfSmrg 22535c4bbdfSmrg /* Damage destination rectangle so that the destination pixmap contents 22635c4bbdfSmrg * will get fully initialized 22735c4bbdfSmrg */ 22835c4bbdfSmrg box.x1 = dirty_update->x; 22935c4bbdfSmrg box.y1 = dirty_update->y; 23035c4bbdfSmrg if (dirty_update->rotation == RR_Rotate_90 || 23135c4bbdfSmrg dirty_update->rotation == RR_Rotate_270) { 2325a112b11Smrg box.x2 = dirty_update->x + secondary_dst->drawable.height; 2335a112b11Smrg box.y2 = dirty_update->y + secondary_dst->drawable.width; 23435c4bbdfSmrg } else { 2355a112b11Smrg box.x2 = dirty_update->x + secondary_dst->drawable.width; 2365a112b11Smrg box.y2 = dirty_update->y + secondary_dst->drawable.height; 23735c4bbdfSmrg } 23835c4bbdfSmrg RegionInit(&dstregion, &box, 1); 23935c4bbdfSmrg damageregion = DamageRegion(dirty_update->damage); 24035c4bbdfSmrg RegionUnion(damageregion, damageregion, &dstregion); 24135c4bbdfSmrg RegionUninit(&dstregion); 24235c4bbdfSmrg 2431b5d61b8Smrg DamageRegister(src, dirty_update->damage); 24435c4bbdfSmrg xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list); 24535c4bbdfSmrg return TRUE; 24635c4bbdfSmrg} 24735c4bbdfSmrg 24835c4bbdfSmrgBool 2495a112b11SmrgPixmapStopDirtyTracking(DrawablePtr src, PixmapPtr secondary_dst) 25035c4bbdfSmrg{ 2511b5d61b8Smrg ScreenPtr screen = src->pScreen; 25235c4bbdfSmrg PixmapDirtyUpdatePtr ent, safe; 25335c4bbdfSmrg 25435c4bbdfSmrg xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { 2555a112b11Smrg if (ent->src == src && ent->secondary_dst == secondary_dst) { 2561b5d61b8Smrg if (ent->damage) 2571b5d61b8Smrg DamageDestroy(ent->damage); 25835c4bbdfSmrg xorg_list_del(&ent->ent); 25935c4bbdfSmrg free(ent); 26035c4bbdfSmrg } 26135c4bbdfSmrg } 26235c4bbdfSmrg return TRUE; 26335c4bbdfSmrg} 26435c4bbdfSmrg 26535c4bbdfSmrgstatic void 26635c4bbdfSmrgPixmapDirtyCopyArea(PixmapPtr dst, 26735c4bbdfSmrg PixmapDirtyUpdatePtr dirty, 26835c4bbdfSmrg RegionPtr dirty_region) 26935c4bbdfSmrg{ 2701b5d61b8Smrg DrawablePtr src = dirty->src; 2711b5d61b8Smrg ScreenPtr pScreen = src->pScreen; 27235c4bbdfSmrg int n; 27335c4bbdfSmrg BoxPtr b; 27435c4bbdfSmrg GCPtr pGC; 27535c4bbdfSmrg 27635c4bbdfSmrg n = RegionNumRects(dirty_region); 27735c4bbdfSmrg b = RegionRects(dirty_region); 27835c4bbdfSmrg 2791b5d61b8Smrg pGC = GetScratchGC(src->depth, pScreen); 2801b5d61b8Smrg if (pScreen->root) { 2811b5d61b8Smrg ChangeGCVal subWindowMode; 2821b5d61b8Smrg 2831b5d61b8Smrg subWindowMode.val = IncludeInferiors; 2841b5d61b8Smrg ChangeGC(NullClient, pGC, GCSubwindowMode, &subWindowMode); 2851b5d61b8Smrg } 28635c4bbdfSmrg ValidateGC(&dst->drawable, pGC); 28735c4bbdfSmrg 28835c4bbdfSmrg while (n--) { 28935c4bbdfSmrg BoxRec dst_box; 29035c4bbdfSmrg int w, h; 29135c4bbdfSmrg 29235c4bbdfSmrg dst_box = *b; 29335c4bbdfSmrg w = dst_box.x2 - dst_box.x1; 29435c4bbdfSmrg h = dst_box.y2 - dst_box.y1; 29535c4bbdfSmrg 2961b5d61b8Smrg pGC->ops->CopyArea(src, &dst->drawable, pGC, 29735c4bbdfSmrg dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, 29835c4bbdfSmrg dirty->dst_x + dst_box.x1, 29935c4bbdfSmrg dirty->dst_y + dst_box.y1); 30035c4bbdfSmrg b++; 30135c4bbdfSmrg } 30235c4bbdfSmrg FreeScratchGC(pGC); 30335c4bbdfSmrg} 30435c4bbdfSmrg 30535c4bbdfSmrgstatic void 30635c4bbdfSmrgPixmapDirtyCompositeRotate(PixmapPtr dst_pixmap, 30735c4bbdfSmrg PixmapDirtyUpdatePtr dirty, 30835c4bbdfSmrg RegionPtr dirty_region) 30935c4bbdfSmrg{ 3101b5d61b8Smrg ScreenPtr pScreen = dirty->src->pScreen; 31135c4bbdfSmrg PictFormatPtr format = PictureWindowFormat(pScreen->root); 31235c4bbdfSmrg PicturePtr src, dst; 31335c4bbdfSmrg XID include_inferiors = IncludeInferiors; 31435c4bbdfSmrg int n = RegionNumRects(dirty_region); 31535c4bbdfSmrg BoxPtr b = RegionRects(dirty_region); 31635c4bbdfSmrg int error; 31735c4bbdfSmrg 31835c4bbdfSmrg src = CreatePicture(None, 3191b5d61b8Smrg dirty->src, 32035c4bbdfSmrg format, 32135c4bbdfSmrg CPSubwindowMode, 32235c4bbdfSmrg &include_inferiors, serverClient, &error); 32335c4bbdfSmrg if (!src) 32435c4bbdfSmrg return; 32535c4bbdfSmrg 32635c4bbdfSmrg dst = CreatePicture(None, 32735c4bbdfSmrg &dst_pixmap->drawable, 32835c4bbdfSmrg format, 0L, NULL, serverClient, &error); 32935c4bbdfSmrg if (!dst) 33035c4bbdfSmrg return; 33135c4bbdfSmrg 33235c4bbdfSmrg error = SetPictureTransform(src, &dirty->transform); 33335c4bbdfSmrg if (error) 33435c4bbdfSmrg return; 33535c4bbdfSmrg while (n--) { 33635c4bbdfSmrg BoxRec dst_box; 33735c4bbdfSmrg 33835c4bbdfSmrg dst_box = *b; 33935c4bbdfSmrg dst_box.x1 += dirty->x; 34035c4bbdfSmrg dst_box.x2 += dirty->x; 34135c4bbdfSmrg dst_box.y1 += dirty->y; 34235c4bbdfSmrg dst_box.y2 += dirty->y; 34335c4bbdfSmrg pixman_f_transform_bounds(&dirty->f_inverse, &dst_box); 34435c4bbdfSmrg 34535c4bbdfSmrg CompositePicture(PictOpSrc, 34635c4bbdfSmrg src, NULL, dst, 34735c4bbdfSmrg dst_box.x1, 34835c4bbdfSmrg dst_box.y1, 34935c4bbdfSmrg 0, 0, 35035c4bbdfSmrg dst_box.x1, 35135c4bbdfSmrg dst_box.y1, 35235c4bbdfSmrg dst_box.x2 - dst_box.x1, 35335c4bbdfSmrg dst_box.y2 - dst_box.y1); 35435c4bbdfSmrg b++; 35535c4bbdfSmrg } 35635c4bbdfSmrg 35735c4bbdfSmrg FreePicture(src, None); 35835c4bbdfSmrg FreePicture(dst, None); 35935c4bbdfSmrg} 36035c4bbdfSmrg 36135c4bbdfSmrg/* 36235c4bbdfSmrg * this function can possibly be improved and optimised, by clipping 36335c4bbdfSmrg * instead of iterating 36435c4bbdfSmrg * Drivers are free to implement their own version of this. 36535c4bbdfSmrg */ 36635c4bbdfSmrgBool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty) 36735c4bbdfSmrg{ 3681b5d61b8Smrg ScreenPtr pScreen = dirty->src->pScreen; 36935c4bbdfSmrg RegionPtr region = DamageRegion(dirty->damage); 37035c4bbdfSmrg PixmapPtr dst; 37135c4bbdfSmrg SourceValidateProcPtr SourceValidate; 37235c4bbdfSmrg RegionRec pixregion; 37335c4bbdfSmrg BoxRec box; 37435c4bbdfSmrg 3755a112b11Smrg dst = dirty->secondary_dst->primary_pixmap; 37635c4bbdfSmrg if (!dst) 3775a112b11Smrg dst = dirty->secondary_dst; 37835c4bbdfSmrg 37935c4bbdfSmrg box.x1 = 0; 38035c4bbdfSmrg box.y1 = 0; 38135c4bbdfSmrg if (dirty->rotation == RR_Rotate_90 || 38235c4bbdfSmrg dirty->rotation == RR_Rotate_270) { 38335c4bbdfSmrg box.x2 = dst->drawable.height; 38435c4bbdfSmrg box.y2 = dst->drawable.width; 38535c4bbdfSmrg } else { 38635c4bbdfSmrg box.x2 = dst->drawable.width; 38735c4bbdfSmrg box.y2 = dst->drawable.height; 38835c4bbdfSmrg } 38935c4bbdfSmrg RegionInit(&pixregion, &box, 1); 39035c4bbdfSmrg 39135c4bbdfSmrg /* 39235c4bbdfSmrg * SourceValidate is used by the software cursor code 39335c4bbdfSmrg * to pull the cursor off of the screen when reading 39435c4bbdfSmrg * bits from the frame buffer. Bypassing this function 39535c4bbdfSmrg * leaves the software cursor in place 39635c4bbdfSmrg */ 39735c4bbdfSmrg SourceValidate = pScreen->SourceValidate; 39825da500fSmrg pScreen->SourceValidate = miSourceValidate; 39935c4bbdfSmrg 40035c4bbdfSmrg RegionTranslate(&pixregion, dirty->x, dirty->y); 40135c4bbdfSmrg RegionIntersect(&pixregion, &pixregion, region); 40235c4bbdfSmrg 40335c4bbdfSmrg if (RegionNil(&pixregion)) { 40435c4bbdfSmrg RegionUninit(&pixregion); 40535c4bbdfSmrg return FALSE; 40635c4bbdfSmrg } 40735c4bbdfSmrg 40835c4bbdfSmrg RegionTranslate(&pixregion, -dirty->x, -dirty->y); 40935c4bbdfSmrg 41035c4bbdfSmrg if (!pScreen->root || dirty->rotation == RR_Rotate_0) 41135c4bbdfSmrg PixmapDirtyCopyArea(dst, dirty, &pixregion); 41235c4bbdfSmrg else 41335c4bbdfSmrg PixmapDirtyCompositeRotate(dst, dirty, &pixregion); 41435c4bbdfSmrg pScreen->SourceValidate = SourceValidate; 41535c4bbdfSmrg return TRUE; 41635c4bbdfSmrg} 417