static Bool update_front(DrawablePtr draw, DRI2BufferPtr front) { int r; PixmapPtr pixmap; struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front); if (draw->type == DRAWABLE_PIXMAP) pixmap = (PixmapPtr)draw; else pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw); pixmap->refcnt++; exaMoveInPixmap(pixmap); r = nouveau_bo_name_get(nouveau_pixmap_bo(pixmap), &front->name); if (r) { (*draw->pScreen->DestroyPixmap)(pixmap); return FALSE; } if (nvbuf->ppix) (*draw->pScreen->DestroyPixmap)(nvbuf->ppix); front->pitch = pixmap->devKind; front->cpp = pixmap->drawable.bitsPerPixel / 8; nvbuf->ppix = pixmap; return TRUE; }
static void ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, int width, int height) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); modesettingPtr ms = modesettingPTR(pScrn); struct exa_context *exa = ms->exa; struct pipe_box src_box; exa_debug_printf("\tExaCopy(srcx=%d, srcy=%d, dstX=%d, dstY=%d, w=%d, h=%d)\n", srcX, srcY, dstX, dstY, width, height); debug_assert(exaGetPixmapDriverPrivate(pDstPixmap) == exa->copy.dst); u_box_2d(srcX, srcY, width, height, &src_box); /* If source and destination overlap, we have to copy to/from a scratch * pixmap. */ if (exa->copy.dst == exa->copy.src && !((dstX + width) < srcX || dstX > (srcX + width) || (dstY + height) < srcY || dstY > (srcY + height))) { struct exa_pixmap_priv *tmp_priv; if (!exa->copy.tmp_pix) { exa->copy.tmp_pix = pScrn->pScreen->CreatePixmap(pScrn->pScreen, pDstPixmap->drawable.width, pDstPixmap->drawable.height, pDstPixmap->drawable.depth, pDstPixmap->drawable.width); exaMoveInPixmap(exa->copy.tmp_pix); } tmp_priv = exaGetPixmapDriverPrivate(exa->copy.tmp_pix); exa->pipe->resource_copy_region( exa->pipe, tmp_priv->tex, 0, srcX, srcY, 0, exa->copy.src->tex, 0, &src_box); exa->pipe->resource_copy_region( exa->pipe, exa->copy.dst->tex, 0, dstX, dstY, 0, tmp_priv->tex, 0, &src_box); } else exa->pipe->resource_copy_region( exa->pipe, exa->copy.dst->tex, 0, dstX, dstY, 0, exa->copy.src->tex, 0, &src_box); }
/** * For the "greedy" migration scheme, pushes the pixmap toward being located in * framebuffer memory. */ static void exaMigrateTowardFb (PixmapPtr pPixmap) { ExaPixmapPriv (pPixmap); if (pExaPixmap == NULL) { DBG_MIGRATE(("UseScreen: ignoring exa-uncontrolled pixmap %p (%s)\n", (pointer)pPixmap, exaPixmapIsOffscreen(pPixmap) ? "s" : "m")); return; } 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) { exaMoveInPixmap(pPixmap); pExaPixmap->score = 0; } if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) pExaPixmap->score++; if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && !exaPixmapIsOffscreen(pPixmap)) { exaMoveInPixmap (pPixmap); } ExaOffscreenMarkUsed (pPixmap); }
/** * Performs migration of the pixmaps according to the operation information * provided in pixmaps and can_accel and the migration scheme chosen in the * config file. */ void exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) { ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; ExaScreenPriv(pScreen); int i, j; /* If this debugging flag is set, check each pixmap for whether it is marked * as clean, and if so, actually check if that's the case. This should help * catch issues with failing to mark a drawable as dirty. While it will * catch them late (after the operation happened), it at least explains what * went wrong, and instrumenting the code to find what operation happened * to the pixmap last shouldn't be hard. */ if (pExaScr->checkDirtyCorrectness) { for (i = 0; i < npixmaps; i++) { if (!exaPixmapIsDirty (pixmaps[i].pPix) && !exaAssertNotDirty (pixmaps[i].pPix)) ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); } } /* If anything is pinned in system memory, we won't be able to * accelerate. */ for (i = 0; i < npixmaps; i++) { if (exaPixmapIsPinned (pixmaps[i].pPix) && !exaPixmapIsOffscreen (pixmaps[i].pPix)) { EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, pixmaps[i].pPix->drawable.width, pixmaps[i].pPix->drawable.height)); can_accel = FALSE; break; } } if (pExaScr->migration == ExaMigrationSmart) { /* If we've got something as a destination that we shouldn't cause to * become newly dirtied, take the unaccelerated route. */ for (i = 0; i < npixmaps; i++) { if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) && !exaPixmapIsDirty (pixmaps[i].pPix)) { for (i = 0; i < npixmaps; i++) { if (!exaPixmapIsDirty (pixmaps[i].pPix)) exaMoveOutPixmap (pixmaps[i].pPix); } return; } } /* If we aren't going to accelerate, then we migrate everybody toward * system memory, and kick out if it's free. */ if (!can_accel) { for (i = 0; i < npixmaps; i++) { exaMigrateTowardSys (pixmaps[i].pPix); if (!exaPixmapIsDirty (pixmaps[i].pPix)) exaMoveOutPixmap (pixmaps[i].pPix); } return; } /* Finally, the acceleration path. Move them all in. */ for (i = 0; i < npixmaps; i++) { exaMigrateTowardFb(pixmaps[i].pPix); exaMoveInPixmap(pixmaps[i].pPix); } } else if (pExaScr->migration == ExaMigrationGreedy) { /* If we can't accelerate, either because the driver can't or because one of * the pixmaps is pinned in system memory, then we migrate everybody toward * system memory. * * We also migrate toward system if all pixmaps involved are currently in * system memory -- this can mitigate thrashing when there are significantly * more pixmaps active than would fit in memory. * * If not, then we migrate toward FB so that hopefully acceleration can * happen. */ if (!can_accel) { for (i = 0; i < npixmaps; i++) exaMigrateTowardSys (pixmaps[i].pPix); return; } for (i = 0; i < npixmaps; i++) { if (exaPixmapIsOffscreen(pixmaps[i].pPix)) { /* Found one in FB, so move all to FB. */ for (j = 0; j < npixmaps; j++) exaMigrateTowardFb(pixmaps[j].pPix); return; } } /* Nobody's in FB, so move all away from FB. */ for (i = 0; i < npixmaps; i++) exaMigrateTowardSys(pixmaps[i].pPix); } else if (pExaScr->migration == ExaMigrationAlways) { /* Always move the pixmaps out if we can't accelerate. If we can * accelerate, try to move them all in. If that fails, then move them * back out. */ if (!can_accel) { for (i = 0; i < npixmaps; i++) exaMoveOutPixmap(pixmaps[i].pPix); return; } /* Now, try to move them all into FB */ for (i = 0; i < npixmaps; i++) { exaMoveInPixmap(pixmaps[i].pPix); ExaOffscreenMarkUsed (pixmaps[i].pPix); } /* If we couldn't fit everything in, then kick back out */ for (i = 0; i < npixmaps; i++) { if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) { EXA_FALLBACK(("Pixmap %p (%dx%d) not in fb\n", pixmaps[i].pPix, pixmaps[i].pPix->drawable.width, pixmaps[i].pPix->drawable.height)); for (j = 0; j < npixmaps; j++) exaMoveOutPixmap(pixmaps[j].pPix); break; } } } }
DRI2BufferPtr nouveau_dri2_create_buffer2(ScreenPtr pScreen, DrawablePtr pDraw, unsigned int attachment, unsigned int format) { NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); struct nouveau_dri2_buffer *nvbuf; struct nouveau_pixmap *nvpix; PixmapPtr ppix = NULL; nvbuf = calloc(1, sizeof(*nvbuf)); if (!nvbuf) return NULL; if (attachment == DRI2BufferFrontLeft) { ppix = get_drawable_pixmap(pDraw); if (pScreen != ppix->drawable.pScreen) ppix = NULL; if (pDraw->type == DRAWABLE_WINDOW) { #if DRI2INFOREC_VERSION >= 6 /* Set initial swap limit on drawable. */ DRI2SwapLimit(pDraw, pNv->swap_limit); #endif } if (ppix) ppix->refcnt++; } else { int bpp; unsigned int usage_hint = NOUVEAU_CREATE_PIXMAP_TILED; /* 'format' is just depth (or 0, or maybe it depends on the caller) */ bpp = round_up_pow2(format ? format : pDraw->depth); if (attachment == DRI2BufferDepth || attachment == DRI2BufferDepthStencil) usage_hint |= NOUVEAU_CREATE_PIXMAP_ZETA; else usage_hint |= NOUVEAU_CREATE_PIXMAP_SCANOUT; ppix = pScreen->CreatePixmap(pScreen, pDraw->width, pDraw->height, bpp, usage_hint); } if (ppix) { pNv->exa_force_cp = TRUE; exaMoveInPixmap(ppix); pNv->exa_force_cp = FALSE; nvbuf->base.pitch = ppix->devKind; nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8; } nvbuf->base.attachment = attachment; nvbuf->base.driverPrivate = nvbuf; nvbuf->base.format = format; nvbuf->base.flags = 0; nvbuf->ppix = ppix; if (ppix) { nvpix = nouveau_pixmap(ppix); if (!nvpix || !nvpix->bo || nouveau_bo_name_get(nvpix->bo, &nvbuf->base.name)) { pScreen->DestroyPixmap(nvbuf->ppix); free(nvbuf); return NULL; } } return &nvbuf->base; }