static Bool ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); modesettingPtr ms = modesettingPTR(pScrn); struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); struct exa_context *exa = ms->exa; exa_debug_printf("ExaPrepareSolid(0x%x)\n", fg); if (!exa->accel) return FALSE; if (!exa->pipe) XORG_FALLBACK("accel not enabled"); if (!priv || !priv->tex) XORG_FALLBACK("%s", !priv ? "!priv" : "!priv->tex"); if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask)) XORG_FALLBACK("planeMask is not solid"); if (alu != GXcopy) XORG_FALLBACK("not GXcopy"); if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, priv->tex->target, 0, PIPE_BIND_RENDER_TARGET)) { XORG_FALLBACK("format %s", util_format_name(priv->tex->format)); } return xorg_solid_bind_state(exa, priv, fg); }
static Bool ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planeMask) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); modesettingPtr ms = modesettingPTR(pScrn); struct exa_context *exa = ms->exa; struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); exa_debug_printf("ExaPrepareCopy\n"); if (!exa->accel) return FALSE; if (!exa->pipe) XORG_FALLBACK("accel not enabled"); if (!priv || !priv->tex) XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex"); if (!src_priv || !src_priv->tex) XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex"); if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) XORG_FALLBACK("planeMask is not solid"); if (alu != GXcopy) XORG_FALLBACK("alu not GXcopy"); if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, priv->tex->target, 0, PIPE_BIND_RENDER_TARGET)) XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format)); if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format, src_priv->tex->target, 0, PIPE_BIND_SAMPLER_VIEW)) XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format)); exa->copy.src = src_priv; exa->copy.dst = priv; return TRUE; }
/** * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. * * This is probably the only case we actually care about. The rest fall through * to migration and fbGetImage, which hopefully will result in migration pushing * the pixmap out of framebuffer. */ void exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPix); int xoff, yoff; Bool ok; if (pExaScr->fallback_counter || pExaScr->swappedOut) goto fallback; /* If there's a system copy, we want to save the result there */ if (pExaPixmap->pDamage) goto fallback; pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) goto fallback; /* Only try to handle the 8bpp and up cases, since we don't want to think * about <8bpp. */ if (pDrawable->bitsPerPixel < 8) goto fallback; ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); if (ok) { exaWaitSync(pDrawable->pScreen); return; } fallback: ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); }
static Bool checkPVR2DBlt(PixmapPtr pPixmap, int alu, Pixel planemask) { if (alu != GXcopy) { DBG("%s: FALSE: (alu != GXcopy)\n", __func__); PERF_INCREMENT(fallback_GXcopy); return FALSE; } if (pPixmap->drawable.bitsPerPixel < 8) { DBG("%s: FALSE: (pPixmap->drawable.bitsPerPixel < 8)\n", __func__); PERF_INCREMENT(fallback_bitsPerPixel); return FALSE; } if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) { DBG("%s: FALSE: (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask))\n", __func__); PERF_INCREMENT(fallback_isSolid); return FALSE; } return TRUE; }
Bool exaHWCopyNtoN(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, Bool upsidedown) { ExaScreenPriv(pDstDrawable->pScreen); PixmapPtr pSrcPixmap, pDstPixmap; ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; int src_off_x, src_off_y; int dst_off_x, dst_off_y; RegionPtr srcregion = NULL, dstregion = NULL; xRectangle *rects; Bool ret = TRUE; /* avoid doing copy operations if no boxes */ if (nbox == 0) return TRUE; pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable); pDstPixmap = exaGetDrawablePixmap(pDstDrawable); exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); rects = malloc(nbox * sizeof(xRectangle)); if (rects) { int i; int ordering; for (i = 0; i < nbox; i++) { rects[i].x = pbox[i].x1 + dx + src_off_x; rects[i].y = pbox[i].y1 + dy + src_off_y; rects[i].width = pbox[i].x2 - pbox[i].x1; rects[i].height = pbox[i].y2 - pbox[i].y1; } /* This must match the RegionCopy() logic for reversing rect order */ if (nbox == 1 || (dx > 0 && dy > 0) || (pDstDrawable != pSrcDrawable && (pDstDrawable->type != DRAWABLE_WINDOW || pSrcDrawable->type != DRAWABLE_WINDOW))) ordering = CT_YXBANDED; else ordering = CT_UNSORTED; srcregion = RegionFromRects(nbox, rects, ordering); free(rects); if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClip != NULL)) { dstregion = RegionCreate(NullBox, 0); RegionCopy(dstregion, srcregion); RegionTranslate(dstregion, dst_off_x - dx - src_off_x, dst_off_y - dy - src_off_y); } } pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap); pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap); /* Check whether the accelerator can use this pixmap. * If the pitch of the pixmaps is out of range, there's nothing * we can do but fall back to software rendering. */ if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) goto fallback; /* If the width or the height of either of the pixmaps * is out of range, check whether the boxes are actually out of the * addressable range as well. If they aren't, we can still do * the copying in hardware. */ if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { int i; for (i = 0; i < nbox; i++) { /* src */ if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) goto fallback; /* dst */ if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) goto fallback; } } if (pExaScr->do_migration) { ExaMigrationRec pixmaps[2]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pDstPixmap; pixmaps[0].pReg = dstregion; pixmaps[1].as_dst = FALSE; pixmaps[1].as_src = TRUE; pixmaps[1].pPix = pSrcPixmap; pixmaps[1].pReg = srcregion; exaDoMigration(pixmaps, 2, TRUE); } /* Mixed directions must be handled specially if the card is lame */ if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && reverse != upsidedown) { if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy)) goto out; goto fallback; } if (exaPixmapHasGpuCopy(pDstPixmap)) { /* Normal blitting. */ if (exaPixmapHasGpuCopy(pSrcPixmap)) { if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) { goto fallback; } while (nbox--) { (*pExaScr->info->Copy) (pDstPixmap, pbox->x1 + dx + src_off_x, pbox->y1 + dy + src_off_y, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } (*pExaScr->info->DoneCopy) (pDstPixmap); exaMarkSync(pDstDrawable->pScreen); /* UTS: mainly for SHM PutImage's secondary path. * * Only taking this path for directly accessible pixmaps. */ } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { int bpp = pSrcDrawable->bitsPerPixel; int src_stride = exaGetPixmapPitch(pSrcPixmap); CARD8 *src = NULL; if (!pExaScr->info->UploadToScreen) goto fallback; if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) goto fallback; if (pSrcDrawable->bitsPerPixel < 8) goto fallback; if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) goto fallback; while (nbox--) { src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); if (!pExaScr->info-> UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, (char *) src, src_stride)) goto fallback; pbox++; } } else goto fallback; } else goto fallback; goto out; fallback: ret = FALSE; out: if (dstregion) { RegionUninit(dstregion); RegionDestroy(dstregion); } if (srcregion) { RegionUninit(srcregion); RegionDestroy(srcregion); } return ret; }
static Bool exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int format, char *bits, int src_stride) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPix); RegionPtr pClip; BoxPtr pbox; int nbox; int xoff, yoff; int bpp = pDrawable->bitsPerPixel; Bool ret = TRUE; if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) return FALSE; /* If there's a system copy, we want to save the result there */ if (pExaPixmap->pDamage) return FALSE; /* Don't bother with under 8bpp, XYPixmaps. */ if (format != ZPixmap || bpp < 8) return FALSE; /* Only accelerate copies: no rop or planemask. */ if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) return FALSE; if (pExaScr->swappedOut) return FALSE; if (pExaScr->do_migration) { ExaMigrationRec pixmaps[1]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPix; pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); exaDoMigration(pixmaps, 1, TRUE); } pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); if (!pPix) return FALSE; x += pDrawable->x; y += pDrawable->y; pClip = fbGetCompositeClip(pGC); for (nbox = RegionNumRects(pClip), pbox = RegionRects(pClip); nbox--; pbox++) { int x1 = x; int y1 = y; int x2 = x + w; int y2 = y + h; char *src; Bool ok; if (x1 < pbox->x1) x1 = pbox->x1; if (y1 < pbox->y1) y1 = pbox->y1; if (x2 > pbox->x2) x2 = pbox->x2; if (y2 > pbox->y2) y2 = pbox->y2; if (x1 >= x2 || y1 >= y2) continue; src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, x2 - x1, y2 - y1, src, src_stride); /* We have to fall back completely, and ignore what has already been completed. * Messing with the fb layer directly like we used to is completely unacceptable. */ if (!ok) { ret = FALSE; break; } } if (ret) exaMarkSync(pDrawable->pScreen); return ret; }
/** * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. * * This is probably the only case we actually care about. The rest fall through * to migration and fbGetImage, which hopefully will result in migration pushing * the pixmap out of framebuffer. */ void exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ExaScreenPriv (pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); int xoff, yoff; Bool ok; if (pExaScr->fallback_counter || pExaScr->swappedOut) goto fallback; exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); if (pExaScr->do_migration) { BoxRec Box; RegionRec Reg; ExaMigrationRec pixmaps[1]; Box.x1 = pDrawable->y + x + xoff; Box.y1 = pDrawable->y + y + yoff; Box.x2 = Box.x1 + w; Box.y2 = Box.y1 + h; REGION_INIT(pScreen, &Reg, &Box, 1); pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; pixmaps[0].pPix = pPix; pixmaps[0].pReg = &Reg; exaDoMigration(pixmaps, 1, FALSE); REGION_UNINIT(pScreen, &Reg); } pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) goto fallback; /* Only try to handle the 8bpp and up cases, since we don't want to think * about <8bpp. */ if (pDrawable->bitsPerPixel < 8) goto fallback; ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); if (ok) { exaWaitSync(pDrawable->pScreen); return; } fallback: ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); }
static Bool ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planeMask) { ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; modesettingPtr ms = modesettingPTR(pScrn); struct exa_context *exa = ms->exa; struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); exa_debug_printf("ExaPrepareCopy\n"); if (!exa->accel) return FALSE; if (!exa->pipe) XORG_FALLBACK("accel not enabled"); if (!priv || !priv->tex) XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex"); if (!src_priv || !src_priv->tex) XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex"); if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) XORG_FALLBACK("planeMask is not solid"); if (alu != GXcopy) XORG_FALLBACK("alu not GXcopy"); if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, priv->tex->target, 0, PIPE_BIND_RENDER_TARGET)) XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format)); if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format, src_priv->tex->target, 0, PIPE_BIND_SAMPLER_VIEW)) XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format)); exa->copy.src = src_priv; exa->copy.dst = priv; /* XXX this used to use resource_copy_region for same-surface copies, * but they were redefined to not allow overlaps (some of the util code * always assumed this anyway). * Drivers should implement accelerated resource_copy_region or it will * be slow - disable for now. */ if (0 && exa->copy.src != exa->copy.dst) { exa->copy.use_surface_copy = TRUE; } else { struct pipe_surface surf_tmpl; exa->copy.use_surface_copy = FALSE; if (exa->copy.dst == exa->copy.src) exa->copy.src_texture = renderer_clone_texture( exa->renderer, exa->copy.src->tex ); else pipe_resource_reference(&exa->copy.src_texture, exa->copy.src->tex); memset(&surf_tmpl, 0, sizeof(surf_tmpl)); u_surface_default_template(&surf_tmpl, exa->copy.dst->tex, PIPE_BIND_RENDER_TARGET); exa->copy.dst_surface = exa->pipe->create_surface(exa->pipe, exa->copy.dst->tex, &surf_tmpl); renderer_copy_prepare(exa->renderer, exa->copy.dst_surface, exa->copy.src_texture ); } return TRUE; }
static Bool ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planeMask) { ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; modesettingPtr ms = modesettingPTR(pScrn); struct exa_context *exa = ms->exa; struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); #if DEBUG_PRINT debug_printf("ExaPrepareCopy\n"); #endif if (!exa->accel) return FALSE; if (!exa->pipe) XORG_FALLBACK("accle not enabled"); if (!priv || !priv->tex) XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex"); if (!src_priv || !src_priv->tex) XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex"); if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) XORG_FALLBACK("planeMask is not solid"); if (alu != GXcopy) XORG_FALLBACK("alu not GXcopy"); if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format, priv->tex->target, PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format)); if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format, src_priv->tex->target, PIPE_TEXTURE_USAGE_SAMPLER, 0)) XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format)); exa->copy.src = src_priv; exa->copy.dst = priv; /* For same-surface copies, the pipe->surface_copy path is clearly * superior, providing it is implemented. In other cases it's not * clear what the better path would be, and eventually we'd * probably want to gather timings and choose dynamically. */ if (exa->pipe->surface_copy && exa->copy.src == exa->copy.dst) { exa->copy.use_surface_copy = TRUE; exa->copy.src_surface = exa->scrn->get_tex_surface( exa->scrn, exa->copy.src->tex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ); exa->copy.dst_surface = exa->scrn->get_tex_surface( exa->scrn, exa->copy.dst->tex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE ); } else { exa->copy.use_surface_copy = FALSE; if (exa->copy.dst == exa->copy.src) exa->copy.src_texture = renderer_clone_texture( exa->renderer, exa->copy.src->tex ); else pipe_texture_reference(&exa->copy.src_texture, exa->copy.src->tex); exa->copy.dst_surface = exa->scrn->get_tex_surface(exa->scrn, exa->copy.dst->tex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE); renderer_copy_prepare(exa->renderer, exa->copy.dst_surface, exa->copy.src_texture ); } return TRUE; }