static int ProcDamageSubtract (ClientPtr client) { REQUEST(xDamageSubtractReq); DamageExtPtr pDamageExt; RegionPtr pRepair; RegionPtr pParts; REQUEST_SIZE_MATCH(xDamageSubtractReq); VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess); VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess); if (pDamageExt->level != DamageReportRawRegion) { DamagePtr pDamage = pDamageExt->pDamage; if (pRepair) { if (pParts) RegionIntersect(pParts, DamageRegion (pDamage), pRepair); if (DamageSubtract (pDamage, pRepair)) DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); } else { if (pParts) RegionCopy(pParts, DamageRegion (pDamage)); DamageEmpty (pDamage); } } return Success; }
static int ProcDamageSubtract (ClientPtr client) { REQUEST(xDamageSubtractReq); DamageExtPtr pDamageExt; RegionPtr pRepair; RegionPtr pParts; REQUEST_SIZE_MATCH(xDamageSubtractReq); VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, SecurityWriteAccess); VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, SecurityWriteAccess); if (pDamageExt->level != DamageReportRawRegion) { DamagePtr pDamage = pDamageExt->pDamage; if (pRepair) { if (pParts) REGION_INTERSECT (prScreen, pParts, DamageRegion (pDamage), pRepair); if (DamageSubtract (pDamage, pRepair)) DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); } else { if (pParts) REGION_COPY (prScreen, pParts, DamageRegion (pDamage)); DamageEmpty (pDamage); } } return (client->noClientException); }
/** * exaPixmapDirty() marks a pixmap as dirty, allowing for * optimizations in pixmap migration when no changes have occurred. */ void exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) { ExaPixmapPriv(pPix); BoxRec box; RegionPtr pDamageReg; RegionRec region; if (!pExaPixmap) return; box.x1 = max(x1, 0); box.y1 = max(y1, 0); box.x2 = min(x2, pPix->drawable.width); box.y2 = min(y2, pPix->drawable.height); if (box.x1 >= box.x2 || box.y1 >= box.y2) return; pDamageReg = DamageRegion(pExaPixmap->pDamage); REGION_INIT(pScreen, ®ion, &box, 1); REGION_UNION(pScreen, pDamageReg, pDamageReg, ®ion); REGION_UNINIT(pScreen, ®ion); }
void xglAddCurrentSurfaceDamage (DrawablePtr pDrawable) { XGL_DRAWABLE_PIXMAP_PRIV (pDrawable); if (BOX_NOTEMPTY (&pPixmapPriv->damageBox)) { RegionRec region; REGION_INIT (pDrawable->pScreen, ®ion, &pPixmapPriv->damageBox, 1); if (pPixmapPriv->pDamage) { RegionPtr pDamageRegion; pDamageRegion = DamageRegion (pPixmapPriv->pDamage); REGION_UNION (pDrawable->pScreen, pDamageRegion, pDamageRegion, ®ion); } REGION_UNION (pDrawable->pScreen, &pPixmapPriv->bitRegion, &pPixmapPriv->bitRegion, ®ion); REGION_UNINIT (pDrawable->pScreen, ®ion); pPixmapPriv->damageBox = miEmptyBox; } }
static void ephyrInternalDamageRedisplay(ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EphyrScrPriv *scrpriv = screen->driver; RegionPtr pRegion; if (!scrpriv || !scrpriv->pDamage) return; pRegion = DamageRegion(scrpriv->pDamage); if (RegionNotEmpty(pRegion)) { int nbox; BoxPtr pbox; if (ephyr_glamor) { ephyr_glamor_damage_redisplay(scrpriv->glamor, pRegion); } else { nbox = RegionNumRects(pRegion); pbox = RegionRects(pRegion); while (nbox--) { hostx_paint_rect(screen, pbox->x1, pbox->y1, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } } DamageEmpty(scrpriv->pDamage); } }
void xglAddSurfaceDamage (DrawablePtr pDrawable, RegionPtr pRegion) { glitz_surface_t *surface; int xOff, yOff; XGL_DRAWABLE_PIXMAP_PRIV (pDrawable); pPixmapPriv->damageBox = miEmptyBox; XGL_GET_DRAWABLE (pDrawable, surface, xOff, yOff); if (xOff || yOff) REGION_TRANSLATE (pDrawable->pScreen, pRegion, xOff, yOff); if (pPixmapPriv->pDamage) { RegionPtr pDamageRegion; pDamageRegion = DamageRegion (pPixmapPriv->pDamage); REGION_UNION (pDrawable->pScreen, pDamageRegion, pDamageRegion, pRegion); } REGION_UNION (pDrawable->pScreen, &pPixmapPriv->bitRegion, &pPixmapPriv->bitRegion, pRegion); if (xOff || yOff) REGION_TRANSLATE (pDrawable->pScreen, pRegion, -xOff, -yOff); }
/** * 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); }
static void NestedShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf) { RegionPtr pRegion = DamageRegion(pBuf->pDamage); NestedClientUpdateScreen(PCLIENTDATA(xf86Screens[pScreen->myNum]), pRegion->extents.x1, pRegion->extents.y1, pRegion->extents.x2, pRegion->extents.y2); }
static int dispatch_dirty_region(ScrnInfoPtr scrn, PixmapPtr pixmap, DamagePtr damage, int fb_id) { modesettingPtr ms = modesettingPTR(scrn); RegionPtr dirty = DamageRegion(damage); unsigned num_cliprects = REGION_NUM_RECTS(dirty); int ret = 0; if (num_cliprects) { drmModeClip *clip = malloc(num_cliprects * sizeof(drmModeClip)); BoxPtr rect = REGION_RECTS(dirty); int i; if (!clip) return -ENOMEM; /* XXX no need for copy? */ for (i = 0; i < num_cliprects; i++, rect++) { clip[i].x1 = rect->x1; clip[i].y1 = rect->y1; clip[i].x2 = rect->x2; clip[i].y2 = rect->y2; } /* TODO query connector property to see if this is needed */ ret = drmModeDirtyFB(ms->fd, fb_id, clip, num_cliprects); free(clip); DamageEmpty(damage); } return ret; }
static CARD32 damage_timer(OsTimerPtr timer, CARD32 time, pointer arg) { struct omap_screen_info *omaps = arg; int needUpdate = 0; RegionPtr region = NULL; #ifdef XSP xspScrPrivPtr xsp_priv = NULL; #endif #ifdef XSP if (xspScrPrivateIndex > 0) { xsp_priv = xspGetScrPriv(omaps->screen->pScreen); if (xsp_priv && xsp_priv->dsp_enabled) needUpdate = 1; } #endif if (!omaps->damage) { omaps->timer_active = 0; omaps->empty_updates = 0; return 0; } #ifdef PROFILE_ME_HARDER omaps->updates++; if (omaps->updates > (5000 / OMAP_UPDATE_TIME)) video_stats(omaps, time); #endif region = DamageRegion(omaps->damage); if (REGION_NOTEMPTY(omaps->screen->pScreen, region)) { accumulate_damage(omaps, region); DamageEmpty(omaps->damage); } if (!region_is_null(omaps)) needUpdate = 1; if (needUpdate) { omaps->empty_updates = 0; update_screen(omaps); } else { omaps->empty_updates++; } #if !defined(PROFILE_ME_HARDER) && !defined(DEBUG) /* Kill the timer if we've gone more than 500ms without an update. */ if (omaps->empty_updates >= 500 / OMAP_UPDATE_TIME) { omaps->timer_active = 0; omaps->empty_updates = 0; return 0; } else #endif { return OMAP_UPDATE_TIME; } }
void shadowUpdateIplan2p4(ScreenPtr pScreen, shadowBufPtr pBuf) { RegionPtr damage = DamageRegion(pBuf->pDamage); PixmapPtr pShadow = pBuf->pPixmap; int nbox = RegionNumRects(damage); BoxPtr pbox = RegionRects(damage); FbBits *shaBase; CARD16 *shaLine, *sha; FbStride shaStride; int scrLine; _X_UNUSED int shaBpp, shaXoff, shaYoff; int x, y, w, h; int i, n; CARD16 *win; _X_UNUSED CARD32 winSize; union { CARD8 bytes[8]; CARD32 words[2]; } d; fbGetDrawable(&pShadow->drawable, shaBase, shaStride, shaBpp, shaXoff, shaYoff); shaStride *= sizeof(FbBits) / sizeof(CARD16); while (nbox--) { x = pbox->x1; y = pbox->y1; w = pbox->x2 - pbox->x1; h = pbox->y2 - pbox->y1; scrLine = (x & -16) / 2; shaLine = (CARD16 *)shaBase + y * shaStride + scrLine / sizeof(CARD16); n = ((x & 15) + w + 15) / 16; /* number of c2p units in scanline */ while (h--) { sha = shaLine; win = (CARD16 *) (*pBuf->window) (pScreen, y, scrLine, SHADOW_WINDOW_WRITE, &winSize, pBuf->closure); if (!win) return; for (i = 0; i < n; i++) { memcpy(d.bytes, sha, sizeof(d.bytes)); c2p_16x4(d.words); store_iplan2p4(win, d.words); sha += sizeof(d.bytes) / sizeof(*sha); win += sizeof(d.bytes) / sizeof(*win); } shaLine += shaStride; y++; } pbox++; } }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * the system memory copy to the framebuffer memory copy. Both areas must be * allocated. */ static void exaCopyDirtyToFb (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (pExaScr->info->UploadToScreen == NULL || !pExaScr->info->UploadToScreen (pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, pExaPixmap->sys_pitch)) { exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST); exaMemcpyBox (pPixmap, pBox, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, pExaPixmap->fb_ptr, pExaPixmap->fb_pitch); exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST); } else do_sync = TRUE; pBox++; } if (do_sync) exaMarkSync (pPixmap->drawable.pScreen); pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; /* The previously damaged bits are now no longer damaged but valid */ REGION_UNION(pPixmap->drawable.pScreen, &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); DamageEmpty (pExaPixmap->pDamage); }
/** * Returns TRUE if the pixmap is dirty (has been modified in its current * location compared to the other), or lacks a private for tracking * dirtiness. */ static Bool exaPixmapIsDirty (PixmapPtr pPix) { ExaPixmapPriv (pPix); return pExaPixmap == NULL || REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)); }
static void shadowRedisplay(ScreenPtr pScreen) { shadowBuf(pScreen); RegionPtr pRegion; if (!pBuf || !pBuf->pDamage || !pBuf->update) return; pRegion = DamageRegion(pBuf->pDamage); if (RegionNotEmpty(pRegion)) { (*pBuf->update) (pScreen, pBuf); DamageEmpty(pBuf->pDamage); } }
static Bool xf86RotateRedisplay(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); DamagePtr damage = xf86_config->rotation_damage; RegionPtr region; if (!damage) return FALSE; xf86RotatePrepare (pScreen); region = DamageRegion(damage); if (REGION_NOTEMPTY(pScreen, region)) { int c; SourceValidateProcPtr SourceValidate; /* * SourceValidate is used by the software cursor code * to pull the cursor off of the screen when reading * bits from the frame buffer. Bypassing this function * leaves the software cursor in place */ SourceValidate = pScreen->SourceValidate; pScreen->SourceValidate = NULL; for (c = 0; c < xf86_config->num_crtc; c++) { xf86CrtcPtr crtc = xf86_config->crtc[c]; if (crtc->rotation != RR_Rotate_0 && crtc->enabled) { RegionRec crtc_damage; /* compute portion of damage that overlaps crtc */ REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); /* update damaged region */ if (REGION_NOTEMPTY(pScreen, &crtc_damage)) xf86RotateCrtcRedisplay (crtc, &crtc_damage); REGION_UNINIT (pScreen, &crtc_damage); } } pScreen->SourceValidate = SourceValidate; DamageEmpty(damage); } return TRUE; }
/** * Returns TRUE if the pixmap is dirty (has been modified in its current * location compared to the other), or lacks a private for tracking * dirtiness. */ static Bool exaPixmapIsDirty(PixmapPtr pPix) { ExaPixmapPriv(pPix); if (pExaPixmap == NULL) EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); if (!pExaPixmap->pDamage) return FALSE; return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) || !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB); }
static void shadowRedisplay(ScreenPtr pScreen) { shadowBuf(pScreen); RegionPtr pRegion; if (!pBuf || !pBuf->pDamage || !pBuf->update) return; /* allow deferral of updates, to minimize overdraw, etc. */ if (!pBuf->ready_to_update(pScreen, pBuf)) return; pRegion = DamageRegion(pBuf->pDamage); if (REGION_NOTEMPTY(pScreen, pRegion)) { (*pBuf->update)(pScreen, pBuf); DamageEmpty(pBuf->pDamage); } }
static void xf86RotateRedisplay(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); DamagePtr damage = xf86_config->rotation_damage; RegionPtr region; if (!damage) return; xf86RotatePrepare (pScreen); region = DamageRegion(damage); if (REGION_NOTEMPTY(pScreen, region)) { int c; for (c = 0; c < xf86_config->num_crtc; c++) { xf86CrtcPtr crtc = xf86_config->crtc[c]; if (crtc->rotation != RR_Rotate_0) { BoxRec box; RegionRec crtc_damage; /* compute portion of damage that overlaps crtc */ box.x1 = crtc->x; box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); box.y1 = crtc->y; box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); REGION_INIT(pScreen, &crtc_damage, &box, 1); REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); /* update damaged region */ if (REGION_NOTEMPTY(pScreen, &crtc_damage)) xf86RotateCrtcRedisplay (crtc, &crtc_damage); REGION_UNINIT (pScreen, &crtc_damage); } } DamageEmpty(damage); } }
static inline RegionPtr saa_pix_damage_region(struct saa_pixmap *spix) { return (spix->damage ? DamageRegion(spix->damage) : NULL); }
Bool xglSyncSurface (DrawablePtr pDrawable) { RegionPtr pRegion; XGL_DRAWABLE_PIXMAP (pDrawable); XGL_PIXMAP_PRIV (pPixmap); if (!pPixmapPriv->surface) { if (!xglCreatePixmapSurface (pPixmap)) return FALSE; } pRegion = DamageRegion (pPixmapPriv->pDamage); if (REGION_NOTEMPTY (pDrawable->pScreen, pRegion)) { glitz_pixel_format_t format; BoxPtr pBox; BoxPtr pExt; int nBox; xglUnmapPixmapBits (pPixmap); nBox = REGION_NUM_RECTS (pRegion); pBox = REGION_RECTS (pRegion); pExt = REGION_EXTENTS (pDrawable->pScreen, pRegion); format.fourcc = pPixmapPriv->pVisual->format.surface->color.fourcc; format.masks = pPixmapPriv->pVisual->pPixel->masks; format.xoffset = pExt->x1; if (pPixmapPriv->stride < 0) { format.skip_lines = pPixmap->drawable.height - pExt->y2; format.bytes_per_line = -pPixmapPriv->stride; format.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; } else { format.skip_lines = pExt->y1; format.bytes_per_line = pPixmapPriv->stride; format.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; } glitz_surface_set_clip_region (pPixmapPriv->surface, 0, 0, (glitz_box_t *) pBox, nBox); glitz_set_pixels (pPixmapPriv->surface, pExt->x1, pExt->y1, pExt->x2 - pExt->x1, pExt->y2 - pExt->y1, &format, pPixmapPriv->buffer); glitz_surface_set_clip_region (pPixmapPriv->surface, 0, 0, NULL, 0); REGION_EMPTY (pDrawable->pScreen, pRegion); } return TRUE; }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * the framebuffer memory copy to the system memory copy. Both areas must be * allocated. */ static void exaCopyDirtyToSys (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (pExaScr->info->DownloadFromScreen == NULL || !pExaScr->info->DownloadFromScreen (pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, pExaPixmap->sys_pitch)) { exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); exaMemcpyBox (pPixmap, pBox, pExaPixmap->fb_ptr, pExaPixmap->fb_pitch, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); } else do_sync = TRUE; pBox++; } /* Make sure the bits have actually landed, since we don't necessarily sync * when accessing pixmaps in system memory. */ if (do_sync) exaWaitSync (pPixmap->drawable.pScreen); pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; /* The previously damaged bits are now no longer damaged but valid */ REGION_UNION(pPixmap->drawable.pScreen, &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); DamageEmpty (pExaPixmap->pDamage); }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * FB to system or vice versa. Both areas must be allocated. */ static void exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, char *sys, int sys_pitch), int fallback_index, void (*sync) (ScreenPtr pScreen)) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv(pPixmap); RegionPtr damage = DamageRegion(pExaPixmap->pDamage); RegionRec CopyReg; Bool save_use_gpu_copy; int save_pitch; BoxPtr pBox; int nbox; Bool access_prepared = FALSE; Bool need_sync = FALSE; /* Damaged bits are valid in current copy but invalid in other one */ if (pExaPixmap->use_gpu_copy) { RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); } else { RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); } RegionEmpty(damage); /* Copy bits valid in source but not in destination */ RegionNull(&CopyReg); RegionSubtract(&CopyReg, pValidSrc, pValidDst); if (migrate->as_dst) { ExaScreenPriv(pPixmap->drawable.pScreen); /* XXX: The pending damage region will be marked as damaged after the * operation, so it should serve as an upper bound for the region that * needs to be synchronized for the operation. Unfortunately, this * causes corruption in some cases, e.g. when starting compiz. See * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . */ if (pExaScr->optimize_migration) { RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); #if DEBUG_MIGRATE if (RegionNil(pending_damage)) { static Bool firsttime = TRUE; if (firsttime) { ErrorF("%s: Pending damage region empty!\n", __func__); firsttime = FALSE; } } #endif /* Try to prevent destination valid region from growing too many * rects by filling it up to the extents of the union of the * destination valid region and the pending damage region. */ if (RegionNumRects(pValidDst) > 10) { BoxRec box; BoxPtr pValidExt, pDamageExt; RegionRec closure; pValidExt = RegionExtents(pValidDst); pDamageExt = RegionExtents(pending_damage); box.x1 = min(pValidExt->x1, pDamageExt->x1); box.y1 = min(pValidExt->y1, pDamageExt->y1); box.x2 = max(pValidExt->x2, pDamageExt->x2); box.y2 = max(pValidExt->y2, pDamageExt->y2); RegionInit(&closure, &box, 0); RegionIntersect(&CopyReg, &CopyReg, &closure); } else RegionIntersect(&CopyReg, &CopyReg, pending_damage); } /* The caller may provide a region to be subtracted from the calculated * dirty region. This is to avoid migration of bits that don't * contribute to the result of the operation. */ if (migrate->pReg) RegionSubtract(&CopyReg, &CopyReg, migrate->pReg); } else { /* The caller may restrict the region to be migrated for source pixmaps * to what's relevant for the operation. */ if (migrate->pReg) RegionIntersect(&CopyReg, &CopyReg, migrate->pReg); } pBox = RegionRects(&CopyReg); nbox = RegionNumRects(&CopyReg); save_use_gpu_copy = pExaPixmap->use_gpu_copy; save_pitch = pPixmap->devKind; pExaPixmap->use_gpu_copy = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (!transfer || !transfer(pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, (char *) (pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), pExaPixmap->sys_pitch)) { if (!access_prepared) { ExaDoPrepareAccess(pPixmap, fallback_index); access_prepared = TRUE; } if (fallback_index == EXA_PREPARE_DEST) { exaMemcpyBox(pPixmap, pBox, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, pPixmap->devPrivate.ptr, pPixmap->devKind); } else { exaMemcpyBox(pPixmap, pBox, pPixmap->devPrivate.ptr, pPixmap->devKind, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); } } else need_sync = TRUE; pBox++; } pExaPixmap->use_gpu_copy = save_use_gpu_copy; pPixmap->devKind = save_pitch; /* Try to prevent source valid region from growing too many rects by * removing parts of it which are also in the destination valid region. * Removing anything beyond that would lead to data loss. */ if (RegionNumRects(pValidSrc) > 20) RegionSubtract(pValidSrc, pValidSrc, pValidDst); /* The copied bits are now valid in destination */ RegionUnion(pValidDst, pValidDst, &CopyReg); RegionUninit(&CopyReg); if (access_prepared) exaFinishAccess(&pPixmap->drawable, fallback_index); else if (need_sync && sync) sync(pPixmap->drawable.pScreen); }