static Bool uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, CARD32 planemask, CARD32 alu) { ScreenPtr screen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(screen); PixmapPtr pixmap; int xoff, yoff; int nbox; BoxPtr pBox; Bool ret = FALSE; pixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); if (!pixmap) return FALSE; REGION_TRANSLATE(screen, pRegion, xoff, yoff); nbox = REGION_NUM_RECTS(pRegion); pBox = REGION_RECTS(pRegion); if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(&pixmap->drawable, alu, planemask)) goto err; if (!uxa_screen->info->prepare_solid(pixmap, alu, planemask, pixel)) goto err; while (nbox--) { uxa_screen->info->solid(pixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2); pBox++; } uxa_screen->info->done_solid(pixmap); ret = TRUE; err: REGION_TRANSLATE(screen, pRegion, -xoff, -yoff); return ret; }
/** * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler. * * It deals with waiting for synchronization with the card, determining if * PrepareAccess() is necessary, and working around PrepareAccess() failure. */ Bool uxa_prepare_access(DrawablePtr pDrawable, RegionPtr region, uxa_access_t access) { ScreenPtr pScreen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); int xoff, yoff; PixmapPtr pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); BoxRec box; RegionRec region_rec; Bool result; if (!pPixmap) return TRUE; if (!region) { box.x1 = 0; box.y1 = 0; box.x2 = pDrawable->width; box.y2 = pDrawable->height; REGION_INIT (pScreen, ®ion_rec, &box, 1); region = ®ion_rec; } else { /* The driver expects a region in drawable coordinates */ REGION_TRANSLATE (pScreen, region, xoff, yoff); } result = TRUE; if (uxa_screen->info->prepare_access) result = (*uxa_screen->info->prepare_access) (pPixmap, region, access); if (region == ®ion_rec) REGION_UNINIT (pScreen, ®ion_rec); return result; }
static void uxa_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle * prect) { uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); RegionPtr pClip = fbGetCompositeClip(pGC); PixmapPtr pPixmap; RegionPtr pReg; BoxPtr pbox; int fullX1, fullX2, fullY1, fullY2; int xoff, yoff; int xorg, yorg; int n; if (uxa_screen->info->flags & UXA_USE_GLAMOR) { int ok = 0; if (uxa_prepare_access(pDrawable, UXA_GLAMOR_ACCESS_RW)) { ok = glamor_poly_fill_rect_nf(pDrawable, pGC, nrect, prect); uxa_finish_access(pDrawable, UXA_GLAMOR_ACCESS_RW); } if (!ok) uxa_check_poly_fill_rect(pDrawable, pGC, nrect, prect); return; } /* Compute intersection of rects and clip region */ pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); REGION_INTERSECT(pScreen, pReg, pClip, pReg); if (!REGION_NUM_RECTS(pReg)) goto out; if (uxa_screen->force_fallback) goto fallback; pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); if (!pPixmap) goto fallback; /* For ROPs where overlaps don't matter, convert rectangles to region * and call uxa_fill_region_{solid,tiled}. */ if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || pGC->alu == GXnoop || pGC->alu == GXcopyInverted || pGC->alu == GXset)) { if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && uxa_fill_region_solid(pDrawable, pReg, pGC->fillStyle == FillSolid ? pGC->fgPixel : pGC->tile. pixel, pGC->planemask, pGC->alu)) || (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && uxa_fill_region_tiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, pGC->planemask, pGC->alu))) { goto out; } } if (pGC->fillStyle != FillSolid && !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) { goto fallback; } if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) { goto fallback; } if (!(*uxa_screen->info->prepare_solid) (pPixmap, pGC->alu, pGC->planemask, pGC->fgPixel)) { fallback: uxa_check_poly_fill_rect(pDrawable, pGC, nrect, prect); goto out; } xorg = pDrawable->x; yorg = pDrawable->y; while (nrect--) { fullX1 = prect->x + xorg; fullY1 = prect->y + yorg; fullX2 = fullX1 + (int)prect->width; fullY2 = fullY1 + (int)prect->height; prect++; n = REGION_NUM_RECTS(pClip); pbox = REGION_RECTS(pClip); /* * clip the rectangle to each box in the clip region * this is logically equivalent to calling Intersect(), * but rectangles may overlap each other here. */ while (n--) { int x1 = fullX1; int x2 = fullX2; int y1 = fullY1; int y2 = fullY2; if (pbox->x1 > x1) x1 = pbox->x1; if (pbox->x2 < x2) x2 = pbox->x2; if (pbox->y1 > y1) y1 = pbox->y1; if (pbox->y2 < y2) y2 = pbox->y2; pbox++; if (x1 >= x2 || y1 >= y2) continue; (*uxa_screen->info->solid) (pPixmap, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff); } } (*uxa_screen->info->done_solid) (pPixmap); out: REGION_UNINIT(pScreen, pReg); REGION_DESTROY(pScreen, pReg); }
static void uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth, int fSorted) { ScreenPtr screen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(screen); RegionPtr pClip = fbGetCompositeClip(pGC); PixmapPtr dst_pixmap; BoxPtr pbox; int nbox; int x1, x2, y; int off_x, off_y; if (uxa_screen->info->flags & UXA_USE_GLAMOR) { int ok = 0; if (uxa_prepare_access(pDrawable, UXA_GLAMOR_ACCESS_RW)) { ok = glamor_fill_spans_nf(pDrawable, pGC, n, ppt, pwidth, fSorted); uxa_finish_access(pDrawable, UXA_GLAMOR_ACCESS_RW); } if (!ok) goto fallback; return; } if (uxa_screen->force_fallback) goto fallback; if (pGC->fillStyle != FillSolid) goto fallback; dst_pixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y); if (!dst_pixmap) goto fallback; if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) goto fallback; if (!(*uxa_screen->info->prepare_solid) (dst_pixmap, pGC->alu, pGC->planemask, pGC->fgPixel)) goto fallback; while (n--) { x1 = ppt->x; y = ppt->y; x2 = x1 + (int)*pwidth; ppt++; pwidth++; nbox = REGION_NUM_RECTS(pClip); pbox = REGION_RECTS(pClip); while (nbox--) { int X1 = x1, X2 = x2; if (X1 < pbox->x1) X1 = pbox->x1; if (X2 > pbox->x2) X2 = pbox->x2; if (X2 > X1 && pbox->y1 <= y && pbox->y2 > y) (*uxa_screen->info->solid) (dst_pixmap, X1 + off_x, y + off_y, X2 + off_x, y + 1 + off_y); pbox++; } } (*uxa_screen->info->done_solid) (dst_pixmap); return; fallback: uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted); }
static Bool inline uxa_copy_n_to_n_two_dir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) { uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); PixmapPtr pSrcPixmap, pDstPixmap; int src_off_x, src_off_y, dst_off_x, dst_off_y; int dirsetup; /* Need to get both pixmaps to call the driver routines */ pSrcPixmap = uxa_get_offscreen_pixmap(pSrcDrawable, &src_off_x, &src_off_y); pDstPixmap = uxa_get_offscreen_pixmap(pDstDrawable, &dst_off_x, &dst_off_y); if (!pSrcPixmap || !pDstPixmap) return FALSE; /* * Now the case of a chip that only supports xdir = ydir = 1 or * xdir = ydir = -1, but we have xdir != ydir. */ dirsetup = 0; /* No direction set up yet. */ for (; nbox; pbox++, nbox--) { if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { /* Do a xdir = ydir = -1 blit instead. */ if (dirsetup != -1) { if (dirsetup != 0) uxa_screen->info->done_copy(pDstPixmap); dirsetup = -1; if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } (*uxa_screen->info->copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, dst_off_y + pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { /* Do a xdir = ydir = 1 blit instead. */ if (dirsetup != 1) { if (dirsetup != 0) uxa_screen->info->done_copy(pDstPixmap); dirsetup = 1; if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } (*uxa_screen->info->copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, dst_off_y + pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (dx >= 0) { /* * xdir = 1, ydir = -1. * Perform line-by-line xdir = ydir = 1 blits, going up. */ int i; if (dirsetup != 1) { if (dirsetup != 0) uxa_screen->info->done_copy(pDstPixmap); dirsetup = 1; if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) (*uxa_screen->info->copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, dst_off_y + pbox->y1 + i, pbox->x2 - pbox->x1, 1); } else { /* * xdir = -1, ydir = 1. * Perform line-by-line xdir = ydir = -1 blits, * going down. */ int i; if (dirsetup != -1) { if (dirsetup != 0) uxa_screen->info->done_copy(pDstPixmap); dirsetup = -1; if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } for (i = 0; i < pbox->y2 - pbox->y1; i++) (*uxa_screen->info->copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, dst_off_y + pbox->y1 + i, pbox->x2 - pbox->x1, 1); } } if (dirsetup != 0) uxa_screen->info->done_copy(pDstPixmap); 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 uxa_get_image(DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ScreenPtr screen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(screen); BoxRec Box; PixmapPtr pPix = uxa_get_drawable_pixmap(pDrawable); int xoff, yoff; Bool ok; uxa_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff); Box.x1 = pDrawable->y + x + xoff; Box.y1 = pDrawable->y + y + yoff; Box.x2 = Box.x1 + w; Box.y2 = Box.y1 + h; if (uxa_screen->info->flags & UXA_USE_GLAMOR) { ok = 0; if (uxa_prepare_access(pDrawable, UXA_GLAMOR_ACCESS_RW)) { ok = glamor_get_image_nf(pDrawable, x, y, w, h, format, planeMask, d); uxa_finish_access(pDrawable, UXA_GLAMOR_ACCESS_RW); } if (!ok) goto fallback; return; } if (uxa_screen->force_fallback) goto fallback; pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); if (pPix == NULL || uxa_screen->info->get_image == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ if (format != ZPixmap || !UXA_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 = uxa_screen->info->get_image(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); if (ok) return; fallback: UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); if (uxa_prepare_access(pDrawable, UXA_ACCESS_RO)) { fbGetImage(pDrawable, x, y, w, h, format, planeMask, d); uxa_finish_access(pDrawable, UXA_ACCESS_RO); } return; }
static Bool uxa_do_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int format, char *bits, int src_stride) { uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); PixmapPtr pPix; RegionPtr pClip; BoxPtr pbox; int nbox; int xoff, yoff; int bpp = pDrawable->bitsPerPixel; /* Don't bother with under 8bpp, XYPixmaps. */ if (format != ZPixmap || bpp < 8) return FALSE; if (uxa_screen->force_fallback) return FALSE; if (!uxa_screen->info->put_image) return FALSE; /* Only accelerate copies: no rop or planemask. */ if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) return FALSE; pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); if (!pPix) return FALSE; x += pDrawable->x; y += pDrawable->y; pClip = fbGetCompositeClip(pGC); for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(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 = uxa_screen->info->put_image(pPix, x1 + xoff, y1 + yoff, x2 - x1, y2 - y1, src, src_stride); /* If we fail to accelerate the upload, fall back to using * unaccelerated fb calls. */ if (!ok) { FbStip *dst; FbStride dst_stride; int dstBpp; int dstXoff, dstYoff; if (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) return FALSE; fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, dstXoff, dstYoff); fbBltStip((FbStip *) bits + (y1 - y) * (src_stride / sizeof(FbStip)), src_stride / sizeof(FbStip), (x1 - x) * dstBpp, dst + (y1 + dstYoff) * dst_stride, dst_stride, (x1 + dstXoff) * dstBpp, (x2 - x1) * dstBpp, y2 - y1, GXcopy, FB_ALLONES, dstBpp); uxa_finish_access(pDrawable, UXA_ACCESS_RW); } } return TRUE; }
/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. * Based on fbFillRegionTiled(), fbTile(). */ Bool uxa_fill_region_tiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu) { uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); PixmapPtr pPixmap; int xoff, yoff; int tileWidth, tileHeight; int nbox = REGION_NUM_RECTS(pRegion); BoxPtr pBox = REGION_RECTS(pRegion); Bool ret = FALSE; tileWidth = pTile->drawable.width; tileHeight = pTile->drawable.height; /* If we're filling with a solid color, grab it out and go to * FillRegionsolid, saving numerous copies. */ if (tileWidth == 1 && tileHeight == 1) return uxa_fill_region_solid(pDrawable, pRegion, uxa_get_pixmap_first_pixel(pTile), planemask, alu); pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) goto out; if (uxa_screen->info->check_copy && !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask)) return FALSE; REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu, planemask)) { while (nbox--) { int height = pBox->y2 - pBox->y1; int dstY = pBox->y1; int tileY; modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); while (height > 0) { int width = pBox->x2 - pBox->x1; int dstX = pBox->x1; int tileX; int h = tileHeight - tileY; if (h > height) h = height; height -= h; modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, tileX); while (width > 0) { int w = tileWidth - tileX; if (w > width) w = width; width -= w; (*uxa_screen->info->copy) (pPixmap, tileX, tileY, dstX, dstY, w, h); dstX += w; tileX = 0; } dstY += h; tileY = 0; } pBox++; } (*uxa_screen->info->done_copy) (pPixmap); ret = TRUE; } out: REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); return ret; }