16747b715Smrg/* 235c4bbdfSmrg * Copyright © 2006 Intel Corporation 36747b715Smrg * 46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a 56747b715Smrg * copy of this software and associated documentation files (the "Software"), 66747b715Smrg * to deal in the Software without restriction, including without limitation 76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the 96747b715Smrg * Software is furnished to do so, subject to the following conditions: 106747b715Smrg * 116747b715Smrg * The above copyright notice and this permission notice (including the next 126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the 136747b715Smrg * Software. 146747b715Smrg * 156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 206747b715Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 216747b715Smrg * SOFTWARE. 226747b715Smrg * 236747b715Smrg * Authors: 246747b715Smrg * Eric Anholt <eric@anholt.net> 2535c4bbdfSmrg * Michel Dänzer <michel@tungstengraphics.com> 266747b715Smrg * 276747b715Smrg */ 286747b715Smrg 296747b715Smrg#ifdef HAVE_DIX_CONFIG_H 306747b715Smrg#include <dix-config.h> 316747b715Smrg#endif 326747b715Smrg 336747b715Smrg#include <string.h> 346747b715Smrg 356747b715Smrg#include "exa_priv.h" 366747b715Smrg#include "exa.h" 376747b715Smrg 386747b715Smrg#if DEBUG_MIGRATE 396747b715Smrg#define DBG_MIGRATE(a) ErrorF a 406747b715Smrg#else 416747b715Smrg#define DBG_MIGRATE(a) 426747b715Smrg#endif 436747b715Smrg 446747b715Smrg/** 456747b715Smrg * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys 466747b715Smrg * and exaCopyDirtyToFb both needed to do this loop. 476747b715Smrg */ 486747b715Smrgstatic void 4935c4bbdfSmrgexaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, 5035c4bbdfSmrg CARD8 *dst, int dst_pitch) 5135c4bbdfSmrg{ 526747b715Smrg int i, cpp = pPixmap->drawable.bitsPerPixel / 8; 536747b715Smrg int bytes = (pbox->x2 - pbox->x1) * cpp; 546747b715Smrg 556747b715Smrg src += pbox->y1 * src_pitch + pbox->x1 * cpp; 566747b715Smrg dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; 576747b715Smrg 586747b715Smrg for (i = pbox->y2 - pbox->y1; i; i--) { 5935c4bbdfSmrg memcpy(dst, src, bytes); 6035c4bbdfSmrg src += src_pitch; 6135c4bbdfSmrg dst += dst_pitch; 626747b715Smrg } 636747b715Smrg} 646747b715Smrg 656747b715Smrg/** 666747b715Smrg * Returns TRUE if the pixmap is dirty (has been modified in its current 676747b715Smrg * location compared to the other), or lacks a private for tracking 686747b715Smrg * dirtiness. 696747b715Smrg */ 706747b715Smrgstatic Bool 7135c4bbdfSmrgexaPixmapIsDirty(PixmapPtr pPix) 726747b715Smrg{ 7335c4bbdfSmrg ExaPixmapPriv(pPix); 746747b715Smrg 756747b715Smrg if (pExaPixmap == NULL) 7635c4bbdfSmrg EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); 776747b715Smrg 786747b715Smrg if (!pExaPixmap->pDamage) 7935c4bbdfSmrg return FALSE; 806747b715Smrg 816747b715Smrg return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) || 8235c4bbdfSmrg !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB); 836747b715Smrg} 846747b715Smrg 856747b715Smrg/** 866747b715Smrg * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score 876747b715Smrg * to be considered "should be in framebuffer". That's just anything that has 886747b715Smrg * had more acceleration than fallbacks, or has no score yet. 896747b715Smrg * 906747b715Smrg * Only valid if using a migration scheme that tracks score. 916747b715Smrg */ 926747b715Smrgstatic Bool 9335c4bbdfSmrgexaPixmapShouldBeInFB(PixmapPtr pPix) 946747b715Smrg{ 9535c4bbdfSmrg ExaPixmapPriv(pPix); 966747b715Smrg 9735c4bbdfSmrg if (exaPixmapIsPinned(pPix)) 9835c4bbdfSmrg return TRUE; 996747b715Smrg 1006747b715Smrg return pExaPixmap->score >= 0; 1016747b715Smrg} 1026747b715Smrg 1036747b715Smrg/** 1046747b715Smrg * If the pixmap is currently dirty, this copies at least the dirty area from 1056747b715Smrg * FB to system or vice versa. Both areas must be allocated. 1066747b715Smrg */ 1076747b715Smrgstatic void 1086747b715SmrgexaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, 10935c4bbdfSmrg Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, 11035c4bbdfSmrg char *sys, int sys_pitch), int fallback_index, 11135c4bbdfSmrg void (*sync) (ScreenPtr pScreen)) 1126747b715Smrg{ 1136747b715Smrg PixmapPtr pPixmap = migrate->pPix; 11435c4bbdfSmrg 11535c4bbdfSmrg ExaPixmapPriv(pPixmap); 11635c4bbdfSmrg RegionPtr damage = DamageRegion(pExaPixmap->pDamage); 1176747b715Smrg RegionRec CopyReg; 1186747b715Smrg Bool save_use_gpu_copy; 1196747b715Smrg int save_pitch; 1206747b715Smrg BoxPtr pBox; 1216747b715Smrg int nbox; 1226747b715Smrg Bool access_prepared = FALSE; 1236747b715Smrg Bool need_sync = FALSE; 1246747b715Smrg 1256747b715Smrg /* Damaged bits are valid in current copy but invalid in other one */ 1266747b715Smrg if (pExaPixmap->use_gpu_copy) { 12735c4bbdfSmrg RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); 12835c4bbdfSmrg RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); 12935c4bbdfSmrg } 13035c4bbdfSmrg else { 13135c4bbdfSmrg RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); 13235c4bbdfSmrg RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); 1336747b715Smrg } 1346747b715Smrg 1356747b715Smrg RegionEmpty(damage); 1366747b715Smrg 1376747b715Smrg /* Copy bits valid in source but not in destination */ 1386747b715Smrg RegionNull(&CopyReg); 1396747b715Smrg RegionSubtract(&CopyReg, pValidSrc, pValidDst); 1406747b715Smrg 1416747b715Smrg if (migrate->as_dst) { 14235c4bbdfSmrg ExaScreenPriv(pPixmap->drawable.pScreen); 1436747b715Smrg 14435c4bbdfSmrg /* XXX: The pending damage region will be marked as damaged after the 14535c4bbdfSmrg * operation, so it should serve as an upper bound for the region that 14635c4bbdfSmrg * needs to be synchronized for the operation. Unfortunately, this 14735c4bbdfSmrg * causes corruption in some cases, e.g. when starting compiz. See 14835c4bbdfSmrg * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . 14935c4bbdfSmrg */ 15035c4bbdfSmrg if (pExaScr->optimize_migration) { 15135c4bbdfSmrg RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); 1526747b715Smrg 1536747b715Smrg#if DEBUG_MIGRATE 15435c4bbdfSmrg if (RegionNil(pending_damage)) { 15535c4bbdfSmrg static Bool firsttime = TRUE; 15635c4bbdfSmrg 15735c4bbdfSmrg if (firsttime) { 15835c4bbdfSmrg ErrorF("%s: Pending damage region empty!\n", __func__); 15935c4bbdfSmrg firsttime = FALSE; 16035c4bbdfSmrg } 16135c4bbdfSmrg } 1626747b715Smrg#endif 1636747b715Smrg 16435c4bbdfSmrg /* Try to prevent destination valid region from growing too many 16535c4bbdfSmrg * rects by filling it up to the extents of the union of the 16635c4bbdfSmrg * destination valid region and the pending damage region. 16735c4bbdfSmrg */ 16835c4bbdfSmrg if (RegionNumRects(pValidDst) > 10) { 16935c4bbdfSmrg BoxRec box; 17035c4bbdfSmrg BoxPtr pValidExt, pDamageExt; 17135c4bbdfSmrg RegionRec closure; 17235c4bbdfSmrg 17335c4bbdfSmrg pValidExt = RegionExtents(pValidDst); 17435c4bbdfSmrg pDamageExt = RegionExtents(pending_damage); 17535c4bbdfSmrg 17635c4bbdfSmrg box.x1 = min(pValidExt->x1, pDamageExt->x1); 17735c4bbdfSmrg box.y1 = min(pValidExt->y1, pDamageExt->y1); 17835c4bbdfSmrg box.x2 = max(pValidExt->x2, pDamageExt->x2); 17935c4bbdfSmrg box.y2 = max(pValidExt->y2, pDamageExt->y2); 18035c4bbdfSmrg 18135c4bbdfSmrg RegionInit(&closure, &box, 0); 18235c4bbdfSmrg RegionIntersect(&CopyReg, &CopyReg, &closure); 18335c4bbdfSmrg } 18435c4bbdfSmrg else 18535c4bbdfSmrg RegionIntersect(&CopyReg, &CopyReg, pending_damage); 18635c4bbdfSmrg } 18735c4bbdfSmrg 18835c4bbdfSmrg /* The caller may provide a region to be subtracted from the calculated 18935c4bbdfSmrg * dirty region. This is to avoid migration of bits that don't 19035c4bbdfSmrg * contribute to the result of the operation. 19135c4bbdfSmrg */ 19235c4bbdfSmrg if (migrate->pReg) 19335c4bbdfSmrg RegionSubtract(&CopyReg, &CopyReg, migrate->pReg); 19435c4bbdfSmrg } 19535c4bbdfSmrg else { 19635c4bbdfSmrg /* The caller may restrict the region to be migrated for source pixmaps 19735c4bbdfSmrg * to what's relevant for the operation. 19835c4bbdfSmrg */ 19935c4bbdfSmrg if (migrate->pReg) 20035c4bbdfSmrg RegionIntersect(&CopyReg, &CopyReg, migrate->pReg); 2016747b715Smrg } 2026747b715Smrg 2036747b715Smrg pBox = RegionRects(&CopyReg); 2046747b715Smrg nbox = RegionNumRects(&CopyReg); 2056747b715Smrg 2066747b715Smrg save_use_gpu_copy = pExaPixmap->use_gpu_copy; 2076747b715Smrg save_pitch = pPixmap->devKind; 2086747b715Smrg pExaPixmap->use_gpu_copy = TRUE; 2096747b715Smrg pPixmap->devKind = pExaPixmap->fb_pitch; 2106747b715Smrg 2116747b715Smrg while (nbox--) { 21235c4bbdfSmrg pBox->x1 = max(pBox->x1, 0); 21335c4bbdfSmrg pBox->y1 = max(pBox->y1, 0); 21435c4bbdfSmrg pBox->x2 = min(pBox->x2, pPixmap->drawable.width); 21535c4bbdfSmrg pBox->y2 = min(pBox->y2, pPixmap->drawable.height); 21635c4bbdfSmrg 21735c4bbdfSmrg if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) 21835c4bbdfSmrg continue; 21935c4bbdfSmrg 22035c4bbdfSmrg if (!transfer || !transfer(pPixmap, 22135c4bbdfSmrg pBox->x1, pBox->y1, 22235c4bbdfSmrg pBox->x2 - pBox->x1, 22335c4bbdfSmrg pBox->y2 - pBox->y1, 22435c4bbdfSmrg (char *) (pExaPixmap->sys_ptr 22535c4bbdfSmrg + pBox->y1 * pExaPixmap->sys_pitch 22635c4bbdfSmrg + 22735c4bbdfSmrg pBox->x1 * 22835c4bbdfSmrg pPixmap->drawable.bitsPerPixel / 22935c4bbdfSmrg 8), pExaPixmap->sys_pitch)) { 23035c4bbdfSmrg if (!access_prepared) { 23135c4bbdfSmrg ExaDoPrepareAccess(pPixmap, fallback_index); 23235c4bbdfSmrg access_prepared = TRUE; 23335c4bbdfSmrg } 23435c4bbdfSmrg if (fallback_index == EXA_PREPARE_DEST) { 23535c4bbdfSmrg exaMemcpyBox(pPixmap, pBox, 23635c4bbdfSmrg pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, 23735c4bbdfSmrg pPixmap->devPrivate.ptr, pPixmap->devKind); 23835c4bbdfSmrg } 23935c4bbdfSmrg else { 24035c4bbdfSmrg exaMemcpyBox(pPixmap, pBox, 24135c4bbdfSmrg pPixmap->devPrivate.ptr, pPixmap->devKind, 24235c4bbdfSmrg pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); 24335c4bbdfSmrg } 24435c4bbdfSmrg } 24535c4bbdfSmrg else 24635c4bbdfSmrg need_sync = TRUE; 24735c4bbdfSmrg 24835c4bbdfSmrg pBox++; 2496747b715Smrg } 2506747b715Smrg 2516747b715Smrg pExaPixmap->use_gpu_copy = save_use_gpu_copy; 2526747b715Smrg pPixmap->devKind = save_pitch; 2536747b715Smrg 2546747b715Smrg /* Try to prevent source valid region from growing too many rects by 2556747b715Smrg * removing parts of it which are also in the destination valid region. 2566747b715Smrg * Removing anything beyond that would lead to data loss. 2576747b715Smrg */ 2586747b715Smrg if (RegionNumRects(pValidSrc) > 20) 25935c4bbdfSmrg RegionSubtract(pValidSrc, pValidSrc, pValidDst); 2606747b715Smrg 2616747b715Smrg /* The copied bits are now valid in destination */ 2626747b715Smrg RegionUnion(pValidDst, pValidDst, &CopyReg); 2636747b715Smrg 2646747b715Smrg RegionUninit(&CopyReg); 2656747b715Smrg 2666747b715Smrg if (access_prepared) 26735c4bbdfSmrg exaFinishAccess(&pPixmap->drawable, fallback_index); 2686747b715Smrg else if (need_sync && sync) 26935c4bbdfSmrg sync(pPixmap->drawable.pScreen); 2706747b715Smrg} 2716747b715Smrg 2726747b715Smrg/** 2736747b715Smrg * If the pixmap is currently dirty, this copies at least the dirty area from 2746747b715Smrg * the framebuffer memory copy to the system memory copy. Both areas must be 2756747b715Smrg * allocated. 2766747b715Smrg */ 2776747b715Smrgvoid 27835c4bbdfSmrgexaCopyDirtyToSys(ExaMigrationPtr migrate) 2796747b715Smrg{ 2806747b715Smrg PixmapPtr pPixmap = migrate->pPix; 28135c4bbdfSmrg 28235c4bbdfSmrg ExaScreenPriv(pPixmap->drawable.pScreen); 28335c4bbdfSmrg ExaPixmapPriv(pPixmap); 2846747b715Smrg 2856747b715Smrg exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB, 28635c4bbdfSmrg pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC, 28735c4bbdfSmrg exaWaitSync); 2886747b715Smrg} 2896747b715Smrg 2906747b715Smrg/** 2916747b715Smrg * If the pixmap is currently dirty, this copies at least the dirty area from 2926747b715Smrg * the system memory copy to the framebuffer memory copy. Both areas must be 2936747b715Smrg * allocated. 2946747b715Smrg */ 2956747b715Smrgvoid 29635c4bbdfSmrgexaCopyDirtyToFb(ExaMigrationPtr migrate) 2976747b715Smrg{ 2986747b715Smrg PixmapPtr pPixmap = migrate->pPix; 29935c4bbdfSmrg 30035c4bbdfSmrg ExaScreenPriv(pPixmap->drawable.pScreen); 30135c4bbdfSmrg ExaPixmapPriv(pPixmap); 3026747b715Smrg 3036747b715Smrg exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys, 30435c4bbdfSmrg pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL); 3056747b715Smrg} 3066747b715Smrg 3076747b715Smrg/** 3086747b715Smrg * Allocates a framebuffer copy of the pixmap if necessary, and then copies 3096747b715Smrg * any necessary pixmap data into the framebuffer copy and points the pixmap at 3106747b715Smrg * it. 3116747b715Smrg * 3126747b715Smrg * Note that when first allocated, a pixmap will have FALSE dirty flag. 3136747b715Smrg * This is intentional because pixmap data starts out undefined. So if we move 3146747b715Smrg * it in due to the first operation against it being accelerated, it will have 3156747b715Smrg * undefined framebuffer contents that we didn't have to upload. If we do 3166747b715Smrg * moveouts (and moveins) after the first movein, then we will only have to copy 3176747b715Smrg * back and forth if the pixmap was written to after the last synchronization of 3186747b715Smrg * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away) 3196747b715Smrg * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move 3206747b715Smrg * all the data, since it's almost surely all valid now. 3216747b715Smrg */ 3226747b715Smrgstatic void 32335c4bbdfSmrgexaDoMoveInPixmap(ExaMigrationPtr migrate) 3246747b715Smrg{ 3256747b715Smrg PixmapPtr pPixmap = migrate->pPix; 3266747b715Smrg ScreenPtr pScreen = pPixmap->drawable.pScreen; 32735c4bbdfSmrg 32835c4bbdfSmrg ExaScreenPriv(pScreen); 32935c4bbdfSmrg ExaPixmapPriv(pPixmap); 3306747b715Smrg 3316747b715Smrg /* If we're VT-switched away, no touching card memory allowed. */ 3326747b715Smrg if (pExaScr->swappedOut) 33335c4bbdfSmrg return; 3346747b715Smrg 3356747b715Smrg /* If we're not allowed to move, then fail. */ 3366747b715Smrg if (exaPixmapIsPinned(pPixmap)) 33735c4bbdfSmrg return; 3386747b715Smrg 3396747b715Smrg /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of 3406747b715Smrg * fragility in EXA, and <8bpp is probably not used enough any more to care 3416747b715Smrg * (at least, not in acceleratd paths). 3426747b715Smrg */ 3436747b715Smrg if (pPixmap->drawable.bitsPerPixel < 8) 34435c4bbdfSmrg return; 3456747b715Smrg 3466747b715Smrg if (pExaPixmap->accel_blocked) 34735c4bbdfSmrg return; 3486747b715Smrg 3496747b715Smrg if (pExaPixmap->area == NULL) { 35035c4bbdfSmrg pExaPixmap->area = 35135c4bbdfSmrg exaOffscreenAlloc(pScreen, pExaPixmap->fb_size, 35235c4bbdfSmrg pExaScr->info->pixmapOffsetAlign, FALSE, 35335c4bbdfSmrg exaPixmapSave, (void *) pPixmap); 35435c4bbdfSmrg if (pExaPixmap->area == NULL) 35535c4bbdfSmrg return; 35635c4bbdfSmrg 35735c4bbdfSmrg pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase + 35835c4bbdfSmrg pExaPixmap->area->offset; 3596747b715Smrg } 3606747b715Smrg 36135c4bbdfSmrg exaCopyDirtyToFb(migrate); 3626747b715Smrg 3636747b715Smrg if (exaPixmapHasGpuCopy(pPixmap)) 36435c4bbdfSmrg return; 3656747b715Smrg 36635c4bbdfSmrg DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, 36735c4bbdfSmrg (ExaGetPixmapPriv(pPixmap)->area ? 36835c4bbdfSmrg ExaGetPixmapPriv(pPixmap)->area->offset : 0), 36935c4bbdfSmrg pPixmap->drawable.width, 37035c4bbdfSmrg pPixmap->drawable.height, 37135c4bbdfSmrg exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); 3726747b715Smrg 3736747b715Smrg pExaPixmap->use_gpu_copy = TRUE; 3746747b715Smrg 3756747b715Smrg pPixmap->devKind = pExaPixmap->fb_pitch; 3766747b715Smrg pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 3776747b715Smrg} 3786747b715Smrg 3796747b715Smrgvoid 38035c4bbdfSmrgexaMoveInPixmap_classic(PixmapPtr pPixmap) 3816747b715Smrg{ 38235c4bbdfSmrg static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE, 38335c4bbdfSmrg .pReg = NULL 38435c4bbdfSmrg }; 3856747b715Smrg 3866747b715Smrg migrate.pPix = pPixmap; 38735c4bbdfSmrg exaDoMoveInPixmap(&migrate); 3886747b715Smrg} 3896747b715Smrg 3906747b715Smrg/** 3916747b715Smrg * Switches the current active location of the pixmap to system memory, copying 3926747b715Smrg * updated data out if necessary. 3936747b715Smrg */ 3946747b715Smrgstatic void 39535c4bbdfSmrgexaDoMoveOutPixmap(ExaMigrationPtr migrate) 3966747b715Smrg{ 3976747b715Smrg PixmapPtr pPixmap = migrate->pPix; 39835c4bbdfSmrg 39935c4bbdfSmrg ExaPixmapPriv(pPixmap); 4006747b715Smrg 4016747b715Smrg if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) 40235c4bbdfSmrg return; 4036747b715Smrg 40435c4bbdfSmrg exaCopyDirtyToSys(migrate); 4056747b715Smrg 4066747b715Smrg if (exaPixmapHasGpuCopy(pPixmap)) { 4076747b715Smrg 40835c4bbdfSmrg DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap, 40935c4bbdfSmrg (void *) (ExaGetPixmapPriv(pPixmap)->area ? 41035c4bbdfSmrg ExaGetPixmapPriv(pPixmap)->area->offset : 0), 41135c4bbdfSmrg pPixmap->drawable.width, 41235c4bbdfSmrg pPixmap->drawable.height, 41335c4bbdfSmrg exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); 4146747b715Smrg 41535c4bbdfSmrg pExaPixmap->use_gpu_copy = FALSE; 4166747b715Smrg 41735c4bbdfSmrg pPixmap->devKind = pExaPixmap->sys_pitch; 41835c4bbdfSmrg pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 4196747b715Smrg } 4206747b715Smrg} 4216747b715Smrg 4226747b715Smrgvoid 42335c4bbdfSmrgexaMoveOutPixmap_classic(PixmapPtr pPixmap) 4246747b715Smrg{ 42535c4bbdfSmrg static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE, 42635c4bbdfSmrg .pReg = NULL 42735c4bbdfSmrg }; 4286747b715Smrg 4296747b715Smrg migrate.pPix = pPixmap; 43035c4bbdfSmrg exaDoMoveOutPixmap(&migrate); 4316747b715Smrg} 4326747b715Smrg 4336747b715Smrg/** 4346747b715Smrg * Copies out important pixmap data and removes references to framebuffer area. 4356747b715Smrg * Called when the memory manager decides it's time to kick the pixmap out of 4366747b715Smrg * framebuffer entirely. 4376747b715Smrg */ 4386747b715Smrgvoid 43935c4bbdfSmrgexaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area) 4406747b715Smrg{ 4416747b715Smrg PixmapPtr pPixmap = area->privData; 44235c4bbdfSmrg 4436747b715Smrg ExaPixmapPriv(pPixmap); 4446747b715Smrg 4456747b715Smrg exaMoveOutPixmap(pPixmap); 4466747b715Smrg 4476747b715Smrg pExaPixmap->fb_ptr = NULL; 4486747b715Smrg pExaPixmap->area = NULL; 4496747b715Smrg 4506747b715Smrg /* Mark all FB bits as invalid, so all valid system bits get copied to FB 4516747b715Smrg * next time */ 4526747b715Smrg RegionEmpty(&pExaPixmap->validFB); 4536747b715Smrg} 4546747b715Smrg 4556747b715Smrg/** 4566747b715Smrg * For the "greedy" migration scheme, pushes the pixmap toward being located in 4576747b715Smrg * framebuffer memory. 4586747b715Smrg */ 4596747b715Smrgstatic void 46035c4bbdfSmrgexaMigrateTowardFb(ExaMigrationPtr migrate) 4616747b715Smrg{ 4626747b715Smrg PixmapPtr pPixmap = migrate->pPix; 46335c4bbdfSmrg 46435c4bbdfSmrg ExaPixmapPriv(pPixmap); 4656747b715Smrg 4666747b715Smrg if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { 46735c4bbdfSmrg DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", 46835c4bbdfSmrg (void *) pPixmap)); 46935c4bbdfSmrg return; 4706747b715Smrg } 4716747b715Smrg 4726747b715Smrg DBG_MIGRATE(("UseScreen %p score %d\n", 47335c4bbdfSmrg (void *) pPixmap, pExaPixmap->score)); 4746747b715Smrg 4756747b715Smrg if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { 47635c4bbdfSmrg exaDoMoveInPixmap(migrate); 47735c4bbdfSmrg pExaPixmap->score = 0; 4786747b715Smrg } 4796747b715Smrg 4806747b715Smrg if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) 48135c4bbdfSmrg pExaPixmap->score++; 4826747b715Smrg 4836747b715Smrg if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && 48435c4bbdfSmrg !exaPixmapHasGpuCopy(pPixmap)) { 48535c4bbdfSmrg exaDoMoveInPixmap(migrate); 4866747b715Smrg } 4876747b715Smrg 4886747b715Smrg if (exaPixmapHasGpuCopy(pPixmap)) { 48935c4bbdfSmrg exaCopyDirtyToFb(migrate); 49035c4bbdfSmrg ExaOffscreenMarkUsed(pPixmap); 49135c4bbdfSmrg } 49235c4bbdfSmrg else 49335c4bbdfSmrg exaCopyDirtyToSys(migrate); 4946747b715Smrg} 4956747b715Smrg 4966747b715Smrg/** 4976747b715Smrg * For the "greedy" migration scheme, pushes the pixmap toward being located in 4986747b715Smrg * system memory. 4996747b715Smrg */ 5006747b715Smrgstatic void 50135c4bbdfSmrgexaMigrateTowardSys(ExaMigrationPtr migrate) 5026747b715Smrg{ 5036747b715Smrg PixmapPtr pPixmap = migrate->pPix; 5046747b715Smrg 50535c4bbdfSmrg ExaPixmapPriv(pPixmap); 50635c4bbdfSmrg 50735c4bbdfSmrg DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap, 50835c4bbdfSmrg pExaPixmap->score)); 5096747b715Smrg 5106747b715Smrg if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) 51135c4bbdfSmrg return; 5126747b715Smrg 5136747b715Smrg if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) 51435c4bbdfSmrg pExaPixmap->score = 0; 5156747b715Smrg 5166747b715Smrg if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) 51735c4bbdfSmrg pExaPixmap->score--; 5186747b715Smrg 5196747b715Smrg if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) 52035c4bbdfSmrg exaDoMoveOutPixmap(migrate); 5216747b715Smrg 5226747b715Smrg if (exaPixmapHasGpuCopy(pPixmap)) { 52335c4bbdfSmrg exaCopyDirtyToFb(migrate); 52435c4bbdfSmrg ExaOffscreenMarkUsed(pPixmap); 52535c4bbdfSmrg } 52635c4bbdfSmrg else 52735c4bbdfSmrg exaCopyDirtyToSys(migrate); 5286747b715Smrg} 5296747b715Smrg 5306747b715Smrg/** 5316747b715Smrg * If the pixmap has both a framebuffer and system memory copy, this function 5326747b715Smrg * asserts that both of them are the same. 5336747b715Smrg */ 5346747b715Smrgstatic Bool 53535c4bbdfSmrgexaAssertNotDirty(PixmapPtr pPixmap) 5366747b715Smrg{ 53735c4bbdfSmrg ExaPixmapPriv(pPixmap); 5386747b715Smrg CARD8 *dst, *src; 5396747b715Smrg RegionRec ValidReg; 5406747b715Smrg int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; 5416747b715Smrg BoxPtr pBox; 5426747b715Smrg Bool ret = TRUE, save_use_gpu_copy; 5436747b715Smrg 5446747b715Smrg if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) 54535c4bbdfSmrg return ret; 5466747b715Smrg 5476747b715Smrg RegionNull(&ValidReg); 54835c4bbdfSmrg RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys); 5496747b715Smrg nbox = RegionNumRects(&ValidReg); 5506747b715Smrg 5516747b715Smrg if (!nbox) 55235c4bbdfSmrg goto out; 5536747b715Smrg 5546747b715Smrg pBox = RegionRects(&ValidReg); 5556747b715Smrg 5566747b715Smrg dst_pitch = pExaPixmap->sys_pitch; 5576747b715Smrg src_pitch = pExaPixmap->fb_pitch; 5586747b715Smrg cpp = pPixmap->drawable.bitsPerPixel / 8; 5596747b715Smrg 5606747b715Smrg save_use_gpu_copy = pExaPixmap->use_gpu_copy; 5616747b715Smrg save_pitch = pPixmap->devKind; 5626747b715Smrg pExaPixmap->use_gpu_copy = TRUE; 5636747b715Smrg pPixmap->devKind = pExaPixmap->fb_pitch; 5646747b715Smrg 5656747b715Smrg if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) 56635c4bbdfSmrg goto skip; 5676747b715Smrg 5686747b715Smrg while (nbox--) { 56935c4bbdfSmrg int rowbytes; 57035c4bbdfSmrg 57135c4bbdfSmrg pBox->x1 = max(pBox->x1, 0); 57235c4bbdfSmrg pBox->y1 = max(pBox->y1, 0); 57335c4bbdfSmrg pBox->x2 = min(pBox->x2, pPixmap->drawable.width); 57435c4bbdfSmrg pBox->y2 = min(pBox->y2, pPixmap->drawable.height); 57535c4bbdfSmrg 57635c4bbdfSmrg if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) 57735c4bbdfSmrg continue; 57835c4bbdfSmrg 57935c4bbdfSmrg rowbytes = (pBox->x2 - pBox->x1) * cpp; 58035c4bbdfSmrg src = 58135c4bbdfSmrg (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + 58235c4bbdfSmrg pBox->x1 * cpp; 58335c4bbdfSmrg dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; 58435c4bbdfSmrg 58535c4bbdfSmrg for (y = pBox->y1; y < pBox->y2; 58635c4bbdfSmrg y++, src += src_pitch, dst += dst_pitch) { 58735c4bbdfSmrg if (memcmp(dst, src, rowbytes) != 0) { 58835c4bbdfSmrg ret = FALSE; 58935c4bbdfSmrg exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2); 59035c4bbdfSmrg break; 59135c4bbdfSmrg } 59235c4bbdfSmrg } 5936747b715Smrg } 5946747b715Smrg 59535c4bbdfSmrg skip: 5966747b715Smrg exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); 5976747b715Smrg 5986747b715Smrg pExaPixmap->use_gpu_copy = save_use_gpu_copy; 5996747b715Smrg pPixmap->devKind = save_pitch; 6006747b715Smrg 60135c4bbdfSmrg out: 6026747b715Smrg RegionUninit(&ValidReg); 6036747b715Smrg return ret; 6046747b715Smrg} 6056747b715Smrg 6066747b715Smrg/** 6076747b715Smrg * Performs migration of the pixmaps according to the operation information 6086747b715Smrg * provided in pixmaps and can_accel and the migration scheme chosen in the 6096747b715Smrg * config file. 6106747b715Smrg */ 6116747b715Smrgvoid 61235c4bbdfSmrgexaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) 6136747b715Smrg{ 6146747b715Smrg ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; 61535c4bbdfSmrg 6166747b715Smrg ExaScreenPriv(pScreen); 6176747b715Smrg int i, j; 6186747b715Smrg 6196747b715Smrg /* If this debugging flag is set, check each pixmap for whether it is marked 6206747b715Smrg * as clean, and if so, actually check if that's the case. This should help 6216747b715Smrg * catch issues with failing to mark a drawable as dirty. While it will 6226747b715Smrg * catch them late (after the operation happened), it at least explains what 6236747b715Smrg * went wrong, and instrumenting the code to find what operation happened 6246747b715Smrg * to the pixmap last shouldn't be hard. 6256747b715Smrg */ 6266747b715Smrg if (pExaScr->checkDirtyCorrectness) { 62735c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 62835c4bbdfSmrg if (!exaPixmapIsDirty(pixmaps[i].pPix) && 62935c4bbdfSmrg !exaAssertNotDirty(pixmaps[i].pPix)) 63035c4bbdfSmrg ErrorF("%s: Pixmap %d dirty but not marked as such!\n", 63135c4bbdfSmrg __func__, i); 63235c4bbdfSmrg } 6336747b715Smrg } 6346747b715Smrg /* If anything is pinned in system memory, we won't be able to 6356747b715Smrg * accelerate. 6366747b715Smrg */ 6376747b715Smrg for (i = 0; i < npixmaps; i++) { 63835c4bbdfSmrg if (exaPixmapIsPinned(pixmaps[i].pPix) && 63935c4bbdfSmrg !exaPixmapHasGpuCopy(pixmaps[i].pPix)) { 64035c4bbdfSmrg EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, 64135c4bbdfSmrg pixmaps[i].pPix->drawable.width, 64235c4bbdfSmrg pixmaps[i].pPix->drawable.height)); 64335c4bbdfSmrg can_accel = FALSE; 64435c4bbdfSmrg break; 64535c4bbdfSmrg } 6466747b715Smrg } 6476747b715Smrg 6486747b715Smrg if (pExaScr->migration == ExaMigrationSmart) { 64935c4bbdfSmrg /* If we've got something as a destination that we shouldn't cause to 65035c4bbdfSmrg * become newly dirtied, take the unaccelerated route. 65135c4bbdfSmrg */ 65235c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 65335c4bbdfSmrg if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) && 65435c4bbdfSmrg !exaPixmapIsDirty(pixmaps[i].pPix)) { 65535c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 65635c4bbdfSmrg if (!exaPixmapIsDirty(pixmaps[i].pPix)) 65735c4bbdfSmrg exaDoMoveOutPixmap(pixmaps + i); 65835c4bbdfSmrg } 65935c4bbdfSmrg return; 66035c4bbdfSmrg } 66135c4bbdfSmrg } 66235c4bbdfSmrg 66335c4bbdfSmrg /* If we aren't going to accelerate, then we migrate everybody toward 66435c4bbdfSmrg * system memory, and kick out if it's free. 66535c4bbdfSmrg */ 66635c4bbdfSmrg if (!can_accel) { 66735c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 66835c4bbdfSmrg exaMigrateTowardSys(pixmaps + i); 66935c4bbdfSmrg if (!exaPixmapIsDirty(pixmaps[i].pPix)) 67035c4bbdfSmrg exaDoMoveOutPixmap(pixmaps + i); 67135c4bbdfSmrg } 67235c4bbdfSmrg return; 67335c4bbdfSmrg } 67435c4bbdfSmrg 67535c4bbdfSmrg /* Finally, the acceleration path. Move them all in. */ 67635c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 67735c4bbdfSmrg exaMigrateTowardFb(pixmaps + i); 67835c4bbdfSmrg exaDoMoveInPixmap(pixmaps + i); 67935c4bbdfSmrg } 68035c4bbdfSmrg } 68135c4bbdfSmrg else if (pExaScr->migration == ExaMigrationGreedy) { 68235c4bbdfSmrg /* If we can't accelerate, either because the driver can't or because one of 68335c4bbdfSmrg * the pixmaps is pinned in system memory, then we migrate everybody toward 68435c4bbdfSmrg * system memory. 68535c4bbdfSmrg * 68635c4bbdfSmrg * We also migrate toward system if all pixmaps involved are currently in 68735c4bbdfSmrg * system memory -- this can mitigate thrashing when there are significantly 68835c4bbdfSmrg * more pixmaps active than would fit in memory. 68935c4bbdfSmrg * 69035c4bbdfSmrg * If not, then we migrate toward FB so that hopefully acceleration can 69135c4bbdfSmrg * happen. 69235c4bbdfSmrg */ 69335c4bbdfSmrg if (!can_accel) { 69435c4bbdfSmrg for (i = 0; i < npixmaps; i++) 69535c4bbdfSmrg exaMigrateTowardSys(pixmaps + i); 69635c4bbdfSmrg return; 69735c4bbdfSmrg } 69835c4bbdfSmrg 69935c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 70035c4bbdfSmrg if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) { 70135c4bbdfSmrg /* Found one in FB, so move all to FB. */ 70235c4bbdfSmrg for (j = 0; j < npixmaps; j++) 70335c4bbdfSmrg exaMigrateTowardFb(pixmaps + i); 70435c4bbdfSmrg return; 70535c4bbdfSmrg } 70635c4bbdfSmrg } 70735c4bbdfSmrg 70835c4bbdfSmrg /* Nobody's in FB, so move all away from FB. */ 70935c4bbdfSmrg for (i = 0; i < npixmaps; i++) 71035c4bbdfSmrg exaMigrateTowardSys(pixmaps + i); 71135c4bbdfSmrg } 71235c4bbdfSmrg else if (pExaScr->migration == ExaMigrationAlways) { 71335c4bbdfSmrg /* Always move the pixmaps out if we can't accelerate. If we can 71435c4bbdfSmrg * accelerate, try to move them all in. If that fails, then move them 71535c4bbdfSmrg * back out. 71635c4bbdfSmrg */ 71735c4bbdfSmrg if (!can_accel) { 71835c4bbdfSmrg for (i = 0; i < npixmaps; i++) 71935c4bbdfSmrg exaDoMoveOutPixmap(pixmaps + i); 72035c4bbdfSmrg return; 72135c4bbdfSmrg } 72235c4bbdfSmrg 72335c4bbdfSmrg /* Now, try to move them all into FB */ 72435c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 72535c4bbdfSmrg exaDoMoveInPixmap(pixmaps + i); 72635c4bbdfSmrg } 72735c4bbdfSmrg 72835c4bbdfSmrg /* If we couldn't fit everything in, abort */ 72935c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 73035c4bbdfSmrg if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) { 73135c4bbdfSmrg return; 73235c4bbdfSmrg } 73335c4bbdfSmrg } 73435c4bbdfSmrg 73535c4bbdfSmrg /* Yay, everything has a gpu copy, mark memory as used */ 73635c4bbdfSmrg for (i = 0; i < npixmaps; i++) { 73735c4bbdfSmrg ExaOffscreenMarkUsed(pixmaps[i].pPix); 73835c4bbdfSmrg } 7396747b715Smrg } 7406747b715Smrg} 7416747b715Smrg 7426747b715Smrgvoid 7436747b715SmrgexaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) 7446747b715Smrg{ 7456747b715Smrg ExaMigrationRec pixmaps[1]; 7466747b715Smrg 7476747b715Smrg if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { 74835c4bbdfSmrg pixmaps[0].as_dst = TRUE; 74935c4bbdfSmrg pixmaps[0].as_src = FALSE; 75035c4bbdfSmrg } 75135c4bbdfSmrg else { 75235c4bbdfSmrg pixmaps[0].as_dst = FALSE; 75335c4bbdfSmrg pixmaps[0].as_src = TRUE; 7546747b715Smrg } 7556747b715Smrg pixmaps[0].pPix = pPixmap; 7566747b715Smrg pixmaps[0].pReg = pReg; 7576747b715Smrg 7586747b715Smrg exaDoMigration(pixmaps, 1, FALSE); 7596747b715Smrg 76035c4bbdfSmrg (void) ExaDoPrepareAccess(pPixmap, index); 7616747b715Smrg} 762