/** * Copies out important pixmap data and removes references to framebuffer area. * Called when the memory manager decides it's time to kick the pixmap out of * framebuffer entirely. */ void exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) { PixmapPtr pPixmap = area->privData; ExaPixmapPriv(pPixmap); RegionPtr pDamageReg = DamageRegion(pExaPixmap->pDamage); DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap, (void*)(ExaGetPixmapPriv(pPixmap)->area ? ExaGetPixmapPriv(pPixmap)->area->offset : 0), pPixmap->drawable.width, pPixmap->drawable.height, exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); if (exaPixmapIsOffscreen(pPixmap)) { exaCopyDirtyToSys (pPixmap); pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devKind = pExaPixmap->sys_pitch; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; } pExaPixmap->fb_ptr = NULL; pExaPixmap->area = NULL; /* Mark all valid bits as damaged, so they'll get copied to FB next time */ REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg, &pExaPixmap->validReg); }
/** * For the "greedy" migration scheme, pushes the pixmap toward being located in * system memory. */ static void exaMigrateTowardSys(ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv(pPixmap); DBG_MIGRATE(("UseMem: %p score %d\n", (pointer) pPixmap, pExaPixmap->score)); if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) return; if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) pExaPixmap->score = 0; if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) pExaPixmap->score--; if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) exaDoMoveOutPixmap(migrate); if (exaPixmapHasGpuCopy(pPixmap)) { exaCopyDirtyToFb(migrate); ExaOffscreenMarkUsed(pPixmap); } else exaCopyDirtyToSys(migrate); }
/** * Switches the current active location of the pixmap to system memory, copying * updated data out if necessary. */ static void exaDoMoveOutPixmap(ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv(pPixmap); if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) return; exaCopyDirtyToSys(migrate); if (exaPixmapHasGpuCopy(pPixmap)) { DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap, (void *) (ExaGetPixmapPriv(pPixmap)->area ? ExaGetPixmapPriv(pPixmap)->area->offset : 0), pPixmap->drawable.width, pPixmap->drawable.height, exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); pExaPixmap->use_gpu_copy = FALSE; pPixmap->devKind = pExaPixmap->sys_pitch; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; } }
/** * Switches the current active location of the pixmap to system memory, copying * updated data out if necessary. */ void exaMoveOutPixmap (PixmapPtr pPixmap) { ExaPixmapPriv (pPixmap); if (exaPixmapIsPinned(pPixmap)) return; if (exaPixmapIsOffscreen(pPixmap)) { DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, (void*)(ExaGetPixmapPriv(pPixmap)->area ? ExaGetPixmapPriv(pPixmap)->area->offset : 0), pPixmap->drawable.width, pPixmap->drawable.height, exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); exaCopyDirtyToSys (pPixmap); pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devKind = pExaPixmap->sys_pitch; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; } }
/** * For the "greedy" migration scheme, pushes the pixmap toward being located in * framebuffer memory. */ static void exaMigrateTowardFb(ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv(pPixmap); if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", (pointer) pPixmap)); return; } DBG_MIGRATE(("UseScreen %p score %d\n", (pointer) pPixmap, pExaPixmap->score)); if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { exaDoMoveInPixmap(migrate); pExaPixmap->score = 0; } if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) pExaPixmap->score++; if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && !exaPixmapHasGpuCopy(pPixmap)) { exaDoMoveInPixmap(migrate); } if (exaPixmapHasGpuCopy(pPixmap)) { exaCopyDirtyToFb(migrate); ExaOffscreenMarkUsed(pPixmap); } else exaCopyDirtyToSys(migrate); }
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we * use the DownloadFromScreen hook to retrieve contents to a copy in system * memory, perform software rendering on that and move back the results with the * UploadToScreen hook (see exaDamageReport_mixed). */ void exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) { ExaPixmapPriv(pPixmap); Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); Bool success; success = ExaDoPrepareAccess(pPixmap, index); if (success && has_gpu_copy && pExaPixmap->pDamage) { /* You cannot do accelerated operations while a buffer is mapped. */ exaFinishAccess(&pPixmap->drawable, index); /* Update the gpu view of both deferred destination pixmaps and of * source pixmaps that were migrated with a bounding region. */ exaMoveInPixmap_mixed(pPixmap); success = ExaDoPrepareAccess(pPixmap, index); if (success) { /* We have a gpu pixmap that can be accessed, we don't need the cpu * copy anymore. Drivers that prefer DFS, should fail prepare * access. */ DamageDestroy(pExaPixmap->pDamage); pExaPixmap->pDamage = NULL; free(pExaPixmap->sys_ptr); pExaPixmap->sys_ptr = NULL; return; } } if (!success) { ExaMigrationRec pixmaps[1]; /* Do we need to allocate our system buffer? */ if (!pExaPixmap->sys_ptr) { pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pPixmap->drawable.height); if (!pExaPixmap->sys_ptr) FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pPixmap->drawable.height); } if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; } else { pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; } pixmaps[0].pPix = pPixmap; pixmaps[0].pReg = pReg; if (!pExaPixmap->pDamage && (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) { Bool as_dst = pixmaps[0].as_dst; /* Set up damage tracking */ pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, DamageReportNonEmpty, TRUE, pPixmap->drawable.pScreen, pPixmap); if (pExaPixmap->pDamage) { DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); /* This ensures that pending damage reflects the current * operation. This is used by exa to optimize migration. */ DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); } if (has_gpu_copy) { exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height); /* We don't know which region of the destination will be damaged, * have to assume all of it */ if (as_dst) { pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; pixmaps[0].pReg = NULL; } exaCopyDirtyToSys(pixmaps); } if (as_dst) exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height); } else if (has_gpu_copy) exaCopyDirtyToSys(pixmaps); pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devKind = pExaPixmap->sys_pitch; pExaPixmap->use_gpu_copy = FALSE; } }